Exemplo n.º 1
0
def create_custom_token(uid, valid_minutes=60):
    """ Create a secure token for the given id.

        This method is used to create secure custom JWT tokens to be passed to
        clients. It takes a unique id that will be used by Firebase's
        security rules to prevent unauthorized access. In this case, the uid will
        be the channel id which is a combination of a user id and a game id.
    """
    now = int(time.time())
    # Encode the required claims
    # per https://firebase.google.com/docs/auth/server/create-custom-tokens
    payload = base64.b64encode(json.dumps({
        'iss': _CLIENT_EMAIL,
        'sub': _CLIENT_EMAIL,
        'aud': _IDENTITY_ENDPOINT,
        'uid': uid, # The field that will be used in Firebase rule enforcement
        'iat': now,
        'exp': now + (valid_minutes * 60),
    }))
    # Add standard header to identify this as a JWT
    header = base64.b64encode(json.dumps({'typ': 'JWT', 'alg': 'RS256'}))
    to_sign = '{}.{}'.format(header, payload)
    # Sign the jwt using the built in app_identity service
    return '{}.{}'.format(to_sign,
        base64.b64encode(app_identity.sign_blob(to_sign, deadline = _TIMEOUT)[1]))
Exemplo n.º 2
0
def create_custom_token(uid, valid_minutes=60):
    """Create a secure token for the given id.
    This method is used to create secure custom JWT tokens to be passed to
    clients. It takes a unique id (uid) that will be used by Firebase's
    security rules to prevent unauthorized access. In this case, the uid will
    be the channel id which is a combination of user_id and game_key
    """

    # use the app_identity service from google.appengine.api to get the
    # project's service account email automatically
    client_email = app_identity.get_service_account_name()

    now = int(time.time())
    # encode the required claims
    # per https://firebase.google.com/docs/auth/server/create-custom-tokens
    payload = base64.b64encode(
        json.dumps({
            'iss': client_email,
            'sub': client_email,
            'aud': _IDENTITY_ENDPOINT,
            'uid':
            uid,  # the important parameter, as it will be the channel id
            'iat': now,
            'exp': now + (valid_minutes * 60),
        }))
    # add standard header to identify this as a JWT
    header = base64.b64encode(json.dumps({'typ': 'JWT', 'alg': 'RS256'}))
    to_sign = '{}.{}'.format(header, payload)
    # Sign the jwt using the built in app_identity service
    return '{}.{}'.format(to_sign,
                          base64.b64encode(app_identity.sign_blob(to_sign)[1]))
Exemplo n.º 3
0
def prepare_upload(bucket_name, path, expiry=DEFAULT_URL_VALID_SECONDS):
    """Prepare a signed GCS upload."""
    expiration_time = (datetime.datetime.utcnow() +
                       datetime.timedelta(seconds=expiry))

    conditions = [
        {
            'key': path
        },
        {
            'bucket': bucket_name
        },
        ['content-length-range', 0, MAX_UPLOAD_SIZE],
        ['starts-with', '$x-goog-meta-filename', ''],
    ]

    policy = base64.b64encode(
        json.dumps({
            'expiration': expiration_time.isoformat() + 'Z',
            'conditions': conditions,
        }))

    local_server = environment.get_value('LOCAL_GCS_SERVER_HOST')
    if local_server:
        url = local_server
        signature = 'SIGNATURE'
        service_account_name = 'service_account'
    else:
        url = STORAGE_URL % bucket_name
        signature = base64.b64encode(app_identity.sign_blob(policy)[1])
        service_account_name = app_identity.get_service_account_name()

    return GcsUpload(url, bucket_name, path, service_account_name, policy,
                     signature)
Exemplo n.º 4
0
def _get_signature_bytes(credentials, string_to_sign):
    """Uses crypto attributes of credentials to sign a string/bytes.

    :type credentials: :class:`client.SignedJwtAssertionCredentials`,
                       :class:`service_account._ServiceAccountCredentials`,
                       :class:`_GAECreds`
    :param credentials: The credentials used for signing text (typically
                        involves the creation of an RSA key).

    :type string_to_sign: string
    :param string_to_sign: The string to be signed by the credentials.

    :rtype: bytes
    :returns: Signed bytes produced by the credentials.
    """
    if isinstance(credentials, _GAECreds):
        _, signed_bytes = app_identity.sign_blob(string_to_sign)
        return signed_bytes
    else:
        pem_key = _get_pem_key(credentials)
        # Sign the string with the RSA key.
        signer = PKCS1_v1_5.new(pem_key)
        if not isinstance(string_to_sign, six.binary_type):
            string_to_sign = string_to_sign.encode('utf-8')
        signature_hash = SHA256.new(string_to_sign)
        return signer.sign(signature_hash)
Exemplo n.º 5
0
def get_signed_url(bucket_name,
                   path,
                   method='GET',
                   expiry=DEFAULT_URL_VALID_SECONDS):
    """Return a signed url."""
    timestamp = _get_expiration_time(expiry)
    blob = '%s\n\n\n%d\n/%s/%s' % (method, timestamp, bucket_name, path)

    local_server = environment.get_value('LOCAL_GCS_SERVER_HOST')
    if local_server:
        url = local_server + '/' + bucket_name
        signed_blob = 'SIGNATURE'
        service_account_name = 'service_account'
    else:
        url = STORAGE_URL % bucket_name
        signed_blob = app_identity.sign_blob(str(blob))[1]
        service_account_name = app_identity.get_service_account_name()

    params = {
        'GoogleAccessId': service_account_name,
        'Expires': timestamp,
        'Signature': base64.b64encode(signed_blob),
    }

    return str(url + '/' + path + '?' + urllib.urlencode(params))
Exemplo n.º 6
0
def generate_jwt():
    """Generates a signed JSON Web Token using the Google App Engine default
    service account."""
    now = int(time.time())

    header_json = json.dumps({
        "typ": "JWT",
        "alg": "RS256"})

    payload_json = json.dumps({
        "iat": now,
        # expires after one hour.
        "exp": now + 3600,
        # iss is the service account email.
        "iss": SERVICE_ACCOUNT_EMAIL,
        # target_audience is the URL of the target service.
        "target_audience": TARGET_AUD,
        # aud must be Google token endpoints URL.
        "aud": "https://www.googleapis.com/oauth2/v4/token"
    })

    header_and_payload = '{}.{}'.format(
        base64.urlsafe_b64encode(header_json),
        base64.urlsafe_b64encode(payload_json))
    (key_name, signature) = app_identity.sign_blob(header_and_payload)
    signed_jwt = '{}.{}'.format(
        header_and_payload,
        base64.urlsafe_b64encode(signature))

    return signed_jwt
Exemplo n.º 7
0
    def GenerateStorageSignedUrl(self, request):
        """Generates signed url for Cloud Storage."""
        GetEndpointsAuthUser()

        if not request.filename:
            raise endpoints.BadRequestException(
                'Missing request field "filename".')
        if not request.owner:
            raise endpoints.BadRequestException(
                'Missing request field "owner".')

        expires = '%sZ' % (datetime.utcnow() +
                           timedelta(hours=1)).isoformat()[:19]
        policy = base64.b64encode(
            json.dumps({
                'expiration':
                expires,
                'conditions': [
                    ['eq', '$bucket', GCS_BUCKET],
                    ['eq', '$key', request.filename],
                    ['eq', '$x-goog-meta-owner', request.owner],
                ],
            }))
        signature = base64.b64encode(app_identity.sign_blob(policy)[1])

        return StorageSignedUrlResponse(
            form_action=GCS_API_URL % GCS_BUCKET,
            bucket=GCS_BUCKET,
            policy=policy,
            signature=signature,
            google_access_id=app_identity.get_service_account_name(),
            filename=request.filename)
Exemplo n.º 8
0
def sign_url(bucket_object, expires_after_seconds=300):
    method = 'GET'
    gcs_filename = urllib.quote('/%s%s' % (settings.FILE_BUCKET, bucket_object))
    content_md5, content_type = None, None

    expiration = datetime.datetime.utcnow() + timedelta(seconds=expires_after_seconds)
    expiration = int(time.mktime(expiration.timetuple()))

    # Generate the string to sign.
    signature_string = '\n'.join([
        method,
        content_md5 or '',
        content_type or '',
        str(expiration),
        gcs_filename])

    _, signature_bytes = app_identity.sign_blob(str(signature_string))
    signature = base64.b64encode(signature_bytes)

    # Set the right query parameters.
    query_params = {'GoogleAccessId': app_identity.get_service_account_name(),
                    'Expires': str(expiration),
                    'Signature': signature}

    # Return the download URL.
    return '{endpoint}{resource}?{querystring}'.format(endpoint=GCS_ACCESS_ENDPOINT,
                                                       resource=gcs_filename,
                                                       querystring=urllib.urlencode(query_params))
Exemplo n.º 9
0
def SignUrl(gcs_filename):
  expiration_dt = _Now() + ATTACHMENT_TTL
  expiration = int(time.mktime(expiration_dt.timetuple()))
  signature_string = '\n'.join([
      'GET',
      '',  # Optional MD5, which we don't have.
      '',  # Optional content-type, which only applies to uploads.
      str(expiration),
      gcs_filename]).encode('utf-8')

  try:
    signature_bytes = app_identity.sign_blob(signature_string)[1]
    query_params = {'GoogleAccessId': app_identity.get_service_account_name(),
                    'Expires': str(expiration),
                    'Signature': base64.b64encode(signature_bytes)}

    result = 'https://storage.googleapis.com{resource}?{querystring}'

    if IS_DEV_APPSERVER:
      result = '/_ah/gcs{resource}?{querystring}'

    return result.format(
          resource=gcs_filename, querystring=urllib.urlencode(query_params))

  except Exception as e:
    logging.exception(e)
    return '/missing-gcs-url'
  def GenerateStorageSignedUrl(self, request):
    """Generates signed url for Cloud Storage."""
    GetEndpointsAuthUser()

    if not request.filename:
      raise endpoints.BadRequestException('Missing request field "filename".')
    if not request.owner:
      raise endpoints.BadRequestException('Missing request field "owner".')

    expires = '%sZ' % (datetime.utcnow() + timedelta(hours=1)).isoformat()[:19]
    policy = base64.b64encode(json.dumps({
        'expiration': expires,
        'conditions': [
            ['eq', '$bucket', GCS_BUCKET],
            ['eq', '$key', request.filename],
            ['eq', '$x-goog-meta-owner', request.owner],
        ],
    }))
    signature = base64.b64encode(app_identity.sign_blob(policy)[1])

    return StorageSignedUrlResponse(
        form_action=GCS_API_URL % GCS_BUCKET,
        bucket=GCS_BUCKET,
        policy=policy,
        signature=signature,
        google_access_id=app_identity.get_service_account_name(),
        filename=request.filename
    )
Exemplo n.º 11
0
def generate_jwt():
    """Generates a signed JSON Web Token using the Google App Engine default
    service account."""
    now = int(time.time())

    header_json = json.dumps({
        "typ": "JWT",
        "alg": "RS256"})

    payload_json = json.dumps({
        "iat": now,
        # expires after one hour.
        "exp": now + 3600,
        # iss is the service account email.
        "iss": SERVICE_ACCOUNT_EMAIL,
        # target_audience is the URL of the target service.
        "target_audience": TARGET_AUD,
        # aud must be Google token endpoints URL.
        "aud": "https://www.googleapis.com/oauth2/v4/token"
    })

    headerAndPayload = '{}.{}'.format(
        base64.urlsafe_b64encode(header_json),
        base64.urlsafe_b64encode(payload_json))
    (key_name, signature) = app_identity.sign_blob(headerAndPayload)
    signed_jwt = '{}.{}'.format(
        headerAndPayload,
        base64.urlsafe_b64encode(signature))

    return signed_jwt
Exemplo n.º 12
0
def _get_signature_bytes(credentials, string_to_sign):
    """Uses crypto attributes of credentials to sign a string/bytes.

    :type credentials: :class:`client.SignedJwtAssertionCredentials`,
                       :class:`service_account._ServiceAccountCredentials`,
                       :class:`_GAECreds`
    :param credentials: The credentials used for signing text (typically
                        involves the creation of an RSA key).

    :type string_to_sign: string
    :param string_to_sign: The string to be signed by the credentials.

    :rtype: bytes
    :returns: Signed bytes produced by the credentials.
    """
    if isinstance(credentials, _GAECreds):
        _, signed_bytes = app_identity.sign_blob(string_to_sign)
        return signed_bytes
    else:
        pem_key = _get_pem_key(credentials)
        # Sign the string with the RSA key.
        signer = PKCS1_v1_5.new(pem_key)
        if not isinstance(string_to_sign, six.binary_type):
            string_to_sign = string_to_sign.encode('utf-8')
        signature_hash = SHA256.new(string_to_sign)
        return signer.sign(signature_hash)
Exemplo n.º 13
0
def generate_jwt():
    """Generates a signed JSON Web Token using the Google App Engine default
    service account."""
    now = int(time.time())

    header_json = json.dumps({
        "typ": "JWT",
        "alg": "RS256"})

    payload_json = json.dumps({
        'iat': now,
        # expires after one hour.
        "exp": now + 3600,
        # iss is the Google App Engine default service account email.
        'iss': DEFAULT_SERVICE_ACCOUNT,
        'sub': DEFAULT_SERVICE_ACCOUNT,
        # aud must match 'audience' in the security configuration in your
        # swagger spec.It can be any string.
        'aud': 'echo.endpoints.sample.google.com',
        "email": DEFAULT_SERVICE_ACCOUNT
    })

    headerAndPayload = '{}.{}'.format(
        base64.urlsafe_b64encode(header_json),
        base64.urlsafe_b64encode(payload_json))
    (key_name, signature) = app_identity.sign_blob(headerAndPayload)
    signed_jwt = '{}.{}'.format(
        headerAndPayload,
        base64.urlsafe_b64encode(signature))

    return signed_jwt
Exemplo n.º 14
0
def create_custom_token(uid, is_premium_account):
    service_account_email = app_identity.get_service_account_name()
    payload = {
        'iss': service_account_email,
        'sub': service_account_email,
        'aud': 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit',
        'uid': uid,
        'claims': {
            'premium_account': is_premium_account
        }
    }
    exp = datetime.timedelta(minutes=60)

    token = jwt.generate_jwt(payload, None, 'RS256', exp)
    header, body, secret = token.split('.')

    # 返ってくるヘッダーは 'alg': 'none' になっているので RS256 に変更
    header = jws.utils.encode({
        'typ': 'JWT',
        'alg': 'RS256'
    }).decode('utf-8')

    # app_identity.sign_blob を使ってサインを作成
    sign = base64.urlsafe_b64encode(app_identity.sign_blob(str(header + '.' + body))[1]).strip('=')

    return header + '.' + body + '.' + sign
Exemplo n.º 15
0
def create_custom_token(uid, valid_minutes=60):
    """Create a secure token for the given id.

    This method is used to create secure custom JWT tokens to be passed to
    clients. It takes a unique id (uid) that will be used by Firebase's
    security rules to prevent unauthorized access. In this case, the uid will
    be the channel id which is a combination of user_id and game_key
    """
    header = base64.b64encode(json.dumps({'typ': 'JWT', 'alg': 'RS256'}))

    client_email = app_identity.get_service_account_name()
    now = int(time.time())
    payload = base64.b64encode(
        json.dumps({
            'iss': client_email,
            'sub': client_email,
            'aud': _IDENTITY_ENDPOINT,
            'uid': uid,
            'iat': now,
            'exp': now + (valid_minutes * 60),
        }))

    to_sign = '{}.{}'.format(header, payload)

    # Sign the jwt
    return '{}.{}'.format(to_sign,
                          base64.b64encode(app_identity.sign_blob(to_sign)[1]))
Exemplo n.º 16
0
def _get_signature_bytes(credentials, string_to_sign):
    """Uses crypto attributes of credentials to sign a string/bytes.

    :type credentials: :class:`service_account.ServiceAccountCredentials`,
                       :class:`_GAECreds`
    :param credentials: The credentials used for signing text (typically
                        involves the creation of a PKey).

    :type string_to_sign: string
    :param string_to_sign: The string to be signed by the credentials.

    :rtype: bytes
    :returns: Signed bytes produced by the credentials.
    :raises: `EnvironmentError` if `crypto` did not import successfully.
    """
    if isinstance(credentials, _GAECreds):
        _, signed_bytes = app_identity.sign_blob(string_to_sign)
        return signed_bytes
    else:
        # Sign the string with the PKey.
        pkey = _get_pem_key(credentials)
        if not isinstance(string_to_sign, six.binary_type):
            string_to_sign = string_to_sign.encode('utf-8')
        if crypto is None:
            raise EnvironmentError(
                'pyOpenSSL must be installed to sign content using a '
                'private key')
        return crypto.sign(pkey, string_to_sign, 'SHA256')
Exemplo n.º 17
0
def create_custom_token(uid, valid_minutes=60):
    """Create a secure token for the given id.

    This method is used to create secure custom JWT tokens to be passed to
    clients. It takes a unique id (uid) that will be used by Firebase's
    security rules to prevent unauthorized access. In this case, the uid will
    be the channel id which is a combination of user_id and game_key
    """

    # use the app_identity service from google.appengine.api to get the
    # project's service account email automatically
    client_email = app_identity.get_service_account_name()

    now = int(time.time())
    # encode the required claims
    # per https://firebase.google.com/docs/auth/server/create-custom-tokens
    payload = base64.b64encode(json.dumps({
        'iss': client_email,
        'sub': client_email,
        'aud': _IDENTITY_ENDPOINT,
        'uid': uid,  # the important parameter, as it will be the channel id
        'iat': now,
        'exp': now + (valid_minutes * 60),
    }))
    # add standard header to identify this as a JWT
    header = base64.b64encode(json.dumps({'typ': 'JWT', 'alg': 'RS256'}))
    to_sign = '{}.{}'.format(header, payload)
    # Sign the jwt using the built in app_identity service
    return '{}.{}'.format(to_sign, base64.b64encode(
        app_identity.sign_blob(to_sign)[1]))
def sign_url(bucket_object, expires_after_seconds=6, bucket=default_bucket):
    """ cloudstorage signed url to download cloudstorage object without login
        Docs : https://cloud.google.com/storage/docs/access-control?hl=bg#Signed-URLs
        API : https://cloud.google.com/storage/docs/reference-methods?hl=bg#getobject
    """

    method = 'GET'
    gcs_filename = urllib.quote('/%s/%s' % (bucket, bucket_object))
    content_md5, content_type = None, None

    # expiration : number of seconds since epoch
    expiration_dt = datetime.utcnow() + timedelta(seconds=expires_after_seconds)
    expiration = int(time.mktime(expiration_dt.timetuple()))

    # Generate the string to sign.
    signature_string = '\n'.join([
        method,
        content_md5 or '',
        content_type or '',
        str(expiration),
        gcs_filename])

    signature_bytes = app_identity.sign_blob(signature_string)[1]

    # Set the right query parameters. we use a gae service account for the id
    query_params = {'GoogleAccessId': google_access_id,
                    'Expires': str(expiration),
                    'Signature': base64.b64encode(signature_bytes)}

    # Return the built URL.
    result = '{endpoint}{resource}?{querystring}'.format(endpoint=GCS_API_ACCESS_ENDPOINT,
                                                         resource=gcs_filename,
                                                         querystring=urllib.urlencode(query_params))
    return result
Exemplo n.º 19
0
def _get_signature_bytes(credentials, string_to_sign):
    """Uses crypto attributes of credentials to sign a string/bytes.

    :type credentials: :class:`service_account.ServiceAccountCredentials`,
                       :class:`_GAECreds`
    :param credentials: The credentials used for signing text (typically
                        involves the creation of a PKey).

    :type string_to_sign: string
    :param string_to_sign: The string to be signed by the credentials.

    :rtype: bytes
    :returns: Signed bytes produced by the credentials.
    :raises: `EnvironmentError` if `crypto` did not import successfully.
    """
    if isinstance(credentials, _GAECreds):
        _, signed_bytes = app_identity.sign_blob(string_to_sign)
        return signed_bytes
    else:
        # Sign the string with the PKey.
        pkey = _get_pem_key(credentials)
        if not isinstance(string_to_sign, six.binary_type):
            string_to_sign = string_to_sign.encode('utf-8')
        if crypto is None:
            raise EnvironmentError(
                'pyOpenSSL must be installed to sign content using a '
                'private key')
        return crypto.sign(pkey, string_to_sign, 'SHA256')
Exemplo n.º 20
0
def generate_jwt():
    """Generates a signed JSON Web Token using the Google App Engine default
    service account."""
    now = int(time.time())

    header_json = json.dumps({
        "typ": "JWT",
        "alg": "RS256"})

    payload_json = json.dumps({
        "iat": now,
        # expires after one hour.
        "exp": now + 3600,
        # iss is the Google App Engine default service account email.
        "iss": DEFAUTL_SERVICE_ACCOUNT,
        # scope must match 'audience' for google_id_token in the security
        # configuration in your swagger spec.
        "scope": TARGET_AUD,
        # aud must be Google token endpoints URL.
        "aud": "https://www.googleapis.com/oauth2/v4/token"
    })

    headerAndPayload = '{}.{}'.format(
        base64.urlsafe_b64encode(header_json),
        base64.urlsafe_b64encode(payload_json))
    (key_name, signature) = app_identity.sign_blob(headerAndPayload)
    signed_jwt = '{}.{}'.format(
        headerAndPayload,
        base64.urlsafe_b64encode(signature))

    return signed_jwt
Exemplo n.º 21
0
def generate_jwt():
    """Generates a signed JSON Web Token using the Google App Engine default
    service account."""
    now = int(time.time())

    header_json = json.dumps({"typ": "JWT", "alg": "RS256"})

    payload_json = json.dumps({
        "iat":
        now,
        # expires after one hour.
        "exp":
        now + 3600,
        # iss is the Google App Engine default service account email.
        "iss":
        DEFAUTL_SERVICE_ACCOUNT,
        # scope must match 'audience' for google_id_token in the security
        # configuration in your swagger spec.
        "scope":
        TARGET_AUD,
        # aud must be Google token endpoints URL.
        "aud":
        "https://www.googleapis.com/oauth2/v4/token"
    })

    headerAndPayload = '{}.{}'.format(base64.urlsafe_b64encode(header_json),
                                      base64.urlsafe_b64encode(payload_json))
    (key_name, signature) = app_identity.sign_blob(headerAndPayload)
    signed_jwt = '{}.{}'.format(headerAndPayload,
                                base64.urlsafe_b64encode(signature))

    return signed_jwt
Exemplo n.º 22
0
def gcs_upload(acl='bucket-owner-read'):
    """ return GCS upload form context
        more info : https://cloud.google.com/storage/docs/xml-api/post-object
    """

    user_id = users.get_current_user().email().lower()
    google_access_id = app_identity.get_service_account_name()
    success_redirect = webapp2.uri_for('gcs_upload_ok', _full=True)
    # GCS signed upload url expires
    expiration_dt = datetime.now() + timedelta(seconds=60)

    # The security json policy document that describes what can and cannot be uploaded in the form
    policy_string = """
    {"expiration": "%s",
              "conditions": [
                  ["starts-with", "$key", ""],
                  {"acl": "%s"},
                  {"success_action_redirect": "%s"},
                  {"success_action_status": "201"},
                  {"x-goog-meta-user-id": "%s"},
              ]}""" % (expiration_dt.replace(microsecond=0).isoformat() + 'Z', acl, success_redirect, user_id)

    # sign the policy document
    policy = base64.b64encode(policy_string)
    _, signature_bytes = app_identity.sign_blob(policy)
    signature = base64.b64encode(signature_bytes)

    logging.debug('GCS upload policy : ' + policy_string)
    return dict(form_bucket=default_bucket, form_access_id=google_access_id, form_policy=policy, form_signature=signature,
                form_succes_redirect=success_redirect, form_user_id=user_id, form_folders=bucket_folders)
Exemplo n.º 23
0
def get_url(path, ttl=15):
    """Returns a signed URL for accessing a resource in the provided path.
    
    Args:
        path - path to the resource
        ttl - signed URL expiry time in minutes
        
    Returns:
        Signed URL to the resource
    """
    expiry = int(round(time.time() + ttl * 60))
    bucket = app_identity.get_default_gcs_bucket_name()
    cpath = '/' + bucket + '/' + path

    data = []
    data.append('GET')          # Method
    data.append('')             # MD5 digest value
    data.append('')             # Content-type
    data.append(str(expiry))    # Expiry date
    data.append(cpath)          # Path to the resource
    data_str = "\n".join(data)
    print(type(data_str))
    
    signing_key_name, signature = app_identity.sign_blob(str(data_str))
    
    url = 'https://storage.googleapis.com'
    url += cpath
    url += '?GoogleAccessId=' + app_identity.get_service_account_name()
    url += '&Expires=' + str(expiry)
    url += '&Signature=' + urllib.quote_plus(base64.b64encode(signature))
    
    return url
Exemplo n.º 24
0
    def key_id(self):
        """Optional[str]: The key ID used to identify this private key.

        .. note::
           This makes a request to the App Identity service.
        """
        key_id, _ = app_identity.sign_blob(b'')
        return key_id
Exemplo n.º 25
0
    def get(self):
        message = 'Hello, world!'
        signing_key_name, signature = app_identity.sign_blob(message)
        verified = verify_signed_by_app(message, signature)

        self.response.content_type = 'text/plain'
        self.response.write('Message: {}\n'.format(message))
        self.response.write(
            'Signature: {}\n'.format(base64.b64encode(signature)))
        self.response.write('Verified: {}\n'.format(verified))
Exemplo n.º 26
0
    def get(self):
        message = 'Hello, world!'
        signing_key_name, signature = app_identity.sign_blob(message)
        verified = verify_signed_by_app(message, signature)

        self.response.content_type = 'text/plain'
        self.response.write('Message: {}\n'.format(message))
        self.response.write('Signature: {}\n'.format(
            base64.b64encode(signature)))
        self.response.write('Verified: {}\n'.format(verified))
Exemplo n.º 27
0
    def sign(message):
        """Signs a message.

        Args:
            message (Union[str, bytes]): The message to be signed.

        Returns:
            bytes: The signature of the message.
        """
        message = _helpers.to_bytes(message)
        return app_identity.sign_blob(message)
Exemplo n.º 28
0
def sign_blob(blob, deadline=None):
  """Signs a blob using current service's private key.

  Just an alias for GAE app_identity.sign_blob function for symmetry with
  'check_signature'. Note that |blob| can be at most 8KB.

  Returns:
    Tuple (name of a key used, RSA+SHA256 signature).
  """
  # app_identity.sign_blob is producing RSA+SHA256 signature. Sadly, it isn't
  # documented anywhere. But it should be relatively stable since this API is
  # used by OAuth2 libraries (and so changing signature method may break a lot
  # of stuff).
  return app_identity.sign_blob(blob, deadline)
Exemplo n.º 29
0
    def sign_blob(self, blob):
        """Cryptographically sign a blob (of bytes).

        Implements abstract method
        :meth:`oauth2client.client.AssertionCredentials.sign_blob`.

        Args:
            blob: bytes, Message to be signed.

        Returns:
            tuple, A pair of the private key ID used to sign the blob and
            the signed contents.
        """
        return app_identity.sign_blob(blob)
Exemplo n.º 30
0
def sign_blob(blob, deadline=None):
    """Signs a blob using current service's private key.

  Just an alias for GAE app_identity.sign_blob function for symmetry with
  'check_signature'. Note that |blob| can be at most 8KB.

  Returns:
    Tuple (name of a key used, RSA+SHA256 signature).
  """
    # app_identity.sign_blob is producing RSA+SHA256 signature. Sadly, it isn't
    # documented anywhere. But it should be relatively stable since this API is
    # used by OAuth2 libraries (and so changing signature method may break a lot
    # of stuff).
    return app_identity.sign_blob(blob, deadline)
Exemplo n.º 31
0
    def sign_blob(self, blob):
        """Cryptographically sign a blob (of bytes).

        Implements abstract method
        :meth:`oauth2client.client.AssertionCredentials.sign_blob`.

        Args:
            blob: bytes, Message to be signed.

        Returns:
            tuple, A pair of the private key ID used to sign the blob and
            the signed contents.
        """
        return app_identity.sign_blob(blob)
Exemplo n.º 32
0
def sign_blob(blob):
    """Signs a blob using current service's private key.

  Uses GAE app_identity.sign_blob function. It has a limit of 8KB on a size of
  a blob, so |blob| is hashed first (with sha512). So final signature is
  RSA+SHA256(sha512(blob)).

  Returns:
    Tuple (name of a key used, signature).
  """
    # app_identity.sign_blob is producing RSA+SHA256 signature. Sadly, it isn't
    # documented anywhere. But it should be relatively stable since this API is
    # used by OAuth2 libraries (and so changing signature method may break a lot
    # of stuff).
    return app_identity.sign_blob(hashlib.sha512(blob).digest())
Exemplo n.º 33
0
	def get(self):
		schema_ver = int(self.request.get('schema'))
		since = self.request.get('since')
		since = "0001-01-01 00:00:00" if since is None or since == "" else since
		since = datetime.datetime.strptime(since, "%Y-%m-%d %H:%M:%S")
		dbversion = models.DBUpdate.query(models.DBUpdate.schema_version == schema_ver, models.DBUpdate.source_time <= since).order(-models.DBUpdate.source_time).get()

		expiry = int(time.time()) + 30
		obj = dbversion.delta_gs_object_name
		obj = obj[3:] if obj[:4] == "/gs/" else obj
		string_to_sign = "GET\n\n\n%d\n%s" % (expiry, obj)
		signature = app_identity.sign_blob(str(string_to_sign))[1]
		query_params = {'GoogleAccessId': app_identity.get_service_account_name(), 'Expires': str(expiry), 'Signature': base64.b64encode(signature)}
		url = '%s%s?%s' % (api_url, obj, urllib.urlencode(query_params))
		return self.redirect(str(url))
Exemplo n.º 34
0
def sign_blob(blob):
  """Signs a blob using current service's private key.

  Uses GAE app_identity.sign_blob function. It has a limit of 8KB on a size of
  a blob, so |blob| is hashed first (with sha512). So final signature is
  RSA+SHA256(sha512(blob)).

  Returns:
    Tuple (name of a key used, signature).
  """
  # app_identity.sign_blob is producing RSA+SHA256 signature. Sadly, it isn't
  # documented anywhere. But it should be relatively stable since this API is
  # used by OAuth2 libraries (and so changing signature method may break a lot
  # of stuff).
  return app_identity.sign_blob(hashlib.sha512(blob).digest())
Exemplo n.º 35
0
def create_custom_token(uid, claims, mobile=False):
    """Create a secure token for the given ids.
    This method is used to create secure custom JWT tokens to be passed to
    clients. It takes a unique id (uid) and a session id (sid) that will be used
    by Firebase's security rules to prevent unauthorized access.

    Args:
        uid (str): a unique id (between 1-36 characters long)
        claims (dict): Additional claims
        mobile (bool): if the mobile service account should be used instead of default service account
    """

    if mobile:
        credentials = json.loads(get_server_settings().mobileFirebaseCredentials)
        client_email = credentials['client_email']
    else:
        # use the app_identity service from google.appengine.api to get the
        # project's service account email automatically
        client_email = app_identity.get_service_account_name()

    now = int(time.time())
    payload = {
        'iss': client_email,
        'sub': client_email,
        'aud': _IDENTITY_ENDPOINT,
        'uid': uid,
        'iat': now,
        'exp': now + 3600,
        'claims': claims
    }
    if mobile:
        return jwt.encode(payload, credentials['private_key'], algorithm=Algorithms.RS256)
    else:
        if DEBUG:
            from google.appengine.api.app_identity.app_identity_stub import APP_SERVICE_ACCOUNT_NAME
            if client_email == APP_SERVICE_ACCOUNT_NAME:
                raise Exception('Cannot create firebase token with default development service account.'
                                ' Set the GOOGLE_APPLICATION_CREDENTIALS environment variable with as value the path '
                                'to a json file containing the credentials for a service account.'
                                ' See https://developers.google.com/identity/protocols/application-default-credentials')
        # encode the required claims
        # per https://firebase.google.com/docs/auth/server/create-custom-tokens
        # uid and sid will be used as channel ids, sid is added to *claims*
        header = b64encode(json.dumps({'typ': 'JWT', 'alg': 'RS256'}))
        encoded_payload = b64encode(json.dumps(payload))
        to_sign = '%s.%s' % (header, encoded_payload)
        return '{}.{}'.format(to_sign, b64encode(app_identity.sign_blob(to_sign)[1]))
Exemplo n.º 36
0
    def sign_url(self, object_name, url_lifetime):
        """ Generates Cloud Storage signed URL to download Google Cloud Storage
        object without sign in.

        See: https://cloud.google.com/storage/docs/access-control/signed-urls
        
        This only works on a real App Engine app, not in a dev app server.
        
        Args:
            object_name (str): The name of the object which is signed.
            url_lifetime (datetime.timedelta): Lifetime of the signed URL. The
                server rejects any requests received after this time from now.
        """
        if utils.is_dev_app_server():
            # Not working on a dev app server because it doesn't support
            # app_identity.sign_blob(). An alternative implementation would
            # be needed to make it work on a dev app server.
            raise Exception(
                'sign_url only works on a real App Engine app, not on a dev '
                'app server.')

        method = 'GET'
        expiration_time = utils.get_utcnow() + url_lifetime
        expiration_sec = int(time.mktime(expiration_time.timetuple()))
        path = '/%s/%s' % (self.bucket_name, object_name)

        # These are unused in our use case.
        content_md5 = ''
        content_type = ''

        signed_text = '\n'.join([
            method,
            content_md5,
            content_type,
            str(expiration_sec),
            path,
        ])
        (_, signature) = app_identity.sign_blob(signed_text.encode('utf-8'))

        query_params = {
            'GoogleAccessId': app_identity.get_service_account_name(),
            'Expires': str(expiration_sec),
            'Signature': base64.b64encode(signature),
        }
        return 'https://storage.googleapis.com%s?%s' % (
            path, urllib.urlencode(query_params))
Exemplo n.º 37
0
    def sign_url(self, object_name, url_lifetime):
        """ Generates Cloud Storage signed URL to download Google Cloud Storage
        object without sign in.

        See: https://cloud.google.com/storage/docs/access-control/signed-urls
        
        This only works on a real App Engine app, not in a dev app server.
        
        Args:
            object_name (str): The name of the object which is signed.
            url_lifetime (datetime.timedelta): Lifetime of the signed URL. The
                server rejects any requests received after this time from now.
        """
        if utils.is_dev_app_server():
            # Not working on a dev app server because it doesn't support
            # app_identity.sign_blob(). An alternative implementation would
            # be needed to make it work on a dev app server.
            raise Exception(
                'sign_url only works on a real App Engine app, not on a dev '
                'app server.')

        method = 'GET'
        expiration_time = utils.get_utcnow() + url_lifetime
        expiration_sec = int(time.mktime(expiration_time.timetuple()))
        path = '/%s/%s' % (self.bucket_name, object_name)

        # These are unused in our use case.
        content_md5 = ''
        content_type = ''

        signed_text = '\n'.join([
            method,
            content_md5,
            content_type,
            str(expiration_sec),
            path,
        ])
        (_, signature) = app_identity.sign_blob(signed_text.encode('utf-8'))

        query_params = {
            'GoogleAccessId': app_identity.get_service_account_name(),
            'Expires': str(expiration_sec),
            'Signature': base64.b64encode(signature),
        }
        return 'https://storage.googleapis.com%s?%s' % (path, urllib.urlencode(query_params))
Exemplo n.º 38
0
def sign_jwt(aud):
    """Produces a JWT signed with app's service account key."""
    now = int(utils.time_time())
    issuer = utils.get_service_account_name()
    claims = {
        'email': issuer,
        'exp': now + 3600,
        'iat': now,
        'iss': issuer,
        'sub': issuer,
    }
    if aud:
        claims['aud'] = aud
    claims_b64 = b64.encode(utils.encode_to_json(claims))
    payload = '.'.join((_jwt_header_b64, claims_b64))
    # TODO(vadimsh): Use sign_jwt RPC to get JWT header with 'kid' populated.
    _, sig = app_identity.sign_blob(payload)
    return '.'.join((payload, b64.encode(sig)))
Exemplo n.º 39
0
def auth_check():
    credentials, project = google.auth.default()
    key_name, signature = app_identity.sign_blob(b'abc')
    scope = 'https://www.googleapis.com/auth/userinfo.email'
    token, expiry = app_identity.get_access_token(scope)
    return code_block(
        '>>> import google.auth',
        '>>> credentials, project = google.auth.default()',
        '>>> credentials',
        repr(credentials),
        '>>> project',
        repr(project),
        '>>> credentials.__dict__',
        repr(credentials.__dict__),
        '>>> from google.appengine.api import app_identity',
        '>>> app_identity',
        repr(app_identity),
        # ALSO: get_access_token_uncached
        # (scopes, service_account_id=None)
        '>>> scope = \'https://www.googleapis.com/auth/userinfo.email\'',
        '>>> token, expiry = app_identity.get_access_token(scope)',
        '>>> token',
        repr(token[:6] + b'...'),
        '>>> expiry',
        repr(expiry),
        '>>> app_identity.get_application_id()',
        repr(app_identity.get_application_id()),
        '>>> app_identity.get_default_gcs_bucket_name()',
        repr(app_identity.get_default_gcs_bucket_name()),
        '>>> app_identity.get_default_version_hostname()',
        repr(app_identity.get_default_version_hostname()),
        '>>> app_identity.get_public_certificates()',
        repr(app_identity.get_public_certificates()),
        '>>> app_identity.get_service_account_name()',
        repr(app_identity.get_service_account_name()),
        '>>> key_name, signature = app_identity.sign_blob(b\'abc\')',
        '>>> key_name',
        repr(key_name),
        '>>> signature',
        repr(signature[:16] + b'...'),
    )
def create_custom_token(uid, sid, valid_minutes=60):
    """Create a secure token for the given ids.
    This method is used to create secure custom JWT tokens to be passed to
    clients. It takes a unique id (uid) and a session id (sid) that will be used
    by Firebase's security rules to prevent unauthorized access.

    Args:
        uid (str): a unique id (between 1-36 characters long)
    """

    # use the app_identity service from google.appengine.api to get the
    # project's service account email automatically
    client_email = app_identity.get_service_account_name()
    if DEBUG:
        from google.appengine.api.app_identity.app_identity_stub import APP_SERVICE_ACCOUNT_NAME
        if client_email == APP_SERVICE_ACCOUNT_NAME:
            raise Exception('Cannot create firebase token with default development service account.'
                            ' Set the GOOGLE_APPLICATION_CREDENTIALS environment variable with as value the path to a '
                            'json file containing the credentials for a service account.'
                            ' See https://developers.google.com/identity/protocols/application-default-credentials')
    now = int(time.time())
    # encode the required claims
    # per https://firebase.google.com/docs/auth/server/create-custom-tokens
    # uid and sid will be used as channel ids, sid is added to *claims*
    payload = base64.b64encode(json.dumps({
        'iss': client_email,
        'sub': client_email,
        'aud': _IDENTITY_ENDPOINT,
        'uid': uid,
        'iat': now,
        'exp': now + (valid_minutes * 60),
        'claims': {
            'sid': sid
        }
    }))
    # add standard header to identify this as a JWT
    header = base64.b64encode(json.dumps({'typ': 'JWT', 'alg': 'RS256'}))
    to_sign = '{}.{}'.format(header, payload)
    # Sign the jwt using the built in app_identity service
    return '{}.{}'.format(to_sign, base64.b64encode(app_identity.sign_blob(to_sign)[1]))
Exemplo n.º 41
0
def sign_gcs_url(gcs_filename, expires_after_seconds=6):
    """ cloudstorage signed url to download cloudstorage object without login
        Docs : https://cloud.google.com/storage/docs/access-control?hl=bg#Signed-URLs
        API : https://cloud.google.com/storage/docs/reference-methods?hl=bg#getobject
    """

    GCS_API_ACCESS_ENDPOINT = 'https://storage.googleapis.com'
    google_access_id = app_identity.get_service_account_name()
    method = 'GET'
    # TODO: decide whether to support content_md5 and content_type as params
    content_md5, content_type = None, None

    # expiration : number of seconds since epoch
    expiration_dt = datetime.utcnow() + timedelta(
        seconds=expires_after_seconds)
    expiration = int(time.mktime(expiration_dt.timetuple()))

    # Generate the string to sign.
    signature_string = '\n'.join([
        method, content_md5 or '', content_type or '',
        str(expiration), gcs_filename
    ])

    signature_bytes = app_identity.sign_blob(str(signature_string))[1]

    # Set the right query parameters. we use a gae service account for the id
    query_params = {
        'GoogleAccessId': google_access_id,
        'Expires': str(expiration),
        'Signature': base64.b64encode(signature_bytes)
    }

    # Return the built URL.
    result = '{endpoint}{resource}?{querystring}'.format(
        endpoint=GCS_API_ACCESS_ENDPOINT,
        resource=gcs_filename,
        querystring=urllib.urlencode(query_params))
    return str(result)
Exemplo n.º 42
0
def gcs_upload(acl='bucket-owner-read'):
    """ return GCS upload form context
        more info : https://cloud.google.com/storage/docs/xml-api/post-object
    """

    user_id = users.get_current_user().email().lower()
    google_access_id = app_identity.get_service_account_name()
    success_redirect = webapp2.uri_for('gcs_upload_ok', _full=True)
    # GCS signed upload url expires
    expiration_dt = datetime.now() + timedelta(seconds=60)

    # The security json policy document that describes what can and cannot be uploaded in the form
    policy_string = """
    {"expiration": "%s",
              "conditions": [
                  ["starts-with", "$key", ""],
                  {"acl": "%s"},
                  {"success_action_redirect": "%s"},
                  {"success_action_status": "201"},
                  {"x-goog-meta-user-id": "%s"},
              ]}""" % (expiration_dt.replace(microsecond=0).isoformat() + 'Z',
                       acl, success_redirect, user_id)

    # sign the policy document
    policy = base64.b64encode(policy_string)
    _, signature_bytes = app_identity.sign_blob(policy)
    signature = base64.b64encode(signature_bytes)

    logging.debug('GCS upload policy : ' + policy_string)
    return dict(form_bucket=default_bucket,
                form_access_id=google_access_id,
                form_policy=policy,
                form_signature=signature,
                form_succes_redirect=success_redirect,
                form_user_id=user_id,
                form_folders=bucket_folders)
Exemplo n.º 43
0
 def _Base64Sign(self, plaintext):
     """Signs and returns a base64-encoded SHA256 digest."""
     _, signature_bytes = app_identity.sign_blob(plaintext)
     return base64.b64encode(signature_bytes)
def generate_gcs_v4_signed_url(bucket_name,
                               object_name,
                               http_method,
                               expiration,
                               query_parameters=None,
                               headers=None):
    """ Generate a signed URL for managing GCS objects using the Cloud Storage V4 signing process.
    Code below heavily borrowed from here: https://cloud.google.com/storage/docs/access-control/signing-urls-manually
    """
    if expiration > 604800:
        print('Expiration Time can\'t be longer than 604800 seconds (7 days).')
        expiration = 604800

    escaped_object_name = quote(object_name, safe='')
    canonical_uri = '/{}/{}'.format(bucket_name, escaped_object_name)

    datetime_now = datetime.utcnow()
    request_timestamp = datetime_now.strftime('%Y%m%dT%H%M%SZ')
    datestamp = datetime_now.strftime('%Y%m%d')

    client_email = app_identity.get_service_account_name()

    credential_scope = '{}/auto/storage/goog4_request'.format(datestamp)
    credential = '{}/{}'.format(client_email, credential_scope)

    if headers is None:
        headers = dict()

    headers['host'] = 'storage.googleapis.com'

    canonical_headers = ''
    ordered_headers = collections.OrderedDict(sorted(headers.items()))
    for k, v in ordered_headers.items():
        lower_k = str(k).lower()
        strip_v = str(v).lower()
        canonical_headers += '{}:{}\n'.format(lower_k, strip_v)

    signed_headers = ''
    for k, _ in ordered_headers.items():
        lower_k = str(k).lower()
        signed_headers += '{};'.format(lower_k)
    signed_headers = signed_headers[:-1]  # remove trailing '&'

    if query_parameters is None:
        query_parameters = dict()

    query_parameters['X-Goog-Algorithm'] = 'GOOG4-RSA-SHA256'
    query_parameters['X-Goog-Credential'] = credential
    query_parameters['X-Goog-Date'] = request_timestamp
    query_parameters['X-Goog-Expires'] = expiration
    query_parameters['X-Goog-SignedHeaders'] = signed_headers

    canonical_query_string = ''
    ordered_query_parameters = collections.OrderedDict(
        sorted(query_parameters.items()))
    for k, v in ordered_query_parameters.items():
        encoded_k = quote(str(k), safe='')
        encoded_v = quote(str(v), safe='')
        canonical_query_string += '{}={}&'.format(encoded_k, encoded_v)
    canonical_query_string = canonical_query_string[:-1]  # remove trailing '&'

    canonical_request = '\n'.join([
        http_method, canonical_uri, canonical_query_string, canonical_headers,
        signed_headers, 'UNSIGNED-PAYLOAD'
    ])

    canonical_request_hash = hashlib.sha256(
        canonical_request.encode()).hexdigest()

    string_to_sign = '\n'.join([
        'GOOG4-RSA-SHA256', request_timestamp, credential_scope,
        canonical_request_hash
    ])

    signing_key_name, signature = app_identity.sign_blob(string_to_sign)
    signature = binascii.hexlify(signature).decode()

    host_name = 'https://storage.googleapis.com'
    signed_url = '{}{}?{}&X-Goog-Signature={}'.format(host_name, canonical_uri,
                                                      canonical_query_string,
                                                      signature)

    return signed_url
Exemplo n.º 45
0
 def get(self):
   encoded_blob = self.request.get('blob').encode('utf-8')
   blob = base64.urlsafe_b64decode(encoded_blob)
   key_name, signature = app_identity.sign_blob(blob)
   json.dump({'key_name': key_name, 'signature': base64.b64encode(signature)},
             self.response)
def test_sign_blob():
    cleartext = 'Curiouser and curiouser!'
    key_name, signature = app_identity.sign_blob(cleartext)
    assert key_name
    assert signature
Exemplo n.º 47
0
 def sign_bytes(self, message):
     return app_identity.sign_blob(message)
Exemplo n.º 48
0
 def sign(self, message):
     message = _helpers.to_bytes(message)
     _, signature = app_identity.sign_blob(message)
     return signature