base.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. # Copyright 2016 Google LLC
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """Base classes for cryptographic signers and verifiers."""
  15. import abc
  16. import io
  17. import json
  18. import six
  19. _JSON_FILE_PRIVATE_KEY = "private_key"
  20. _JSON_FILE_PRIVATE_KEY_ID = "private_key_id"
  21. @six.add_metaclass(abc.ABCMeta)
  22. class Verifier(object):
  23. """Abstract base class for crytographic signature verifiers."""
  24. @abc.abstractmethod
  25. def verify(self, message, signature):
  26. """Verifies a message against a cryptographic signature.
  27. Args:
  28. message (Union[str, bytes]): The message to verify.
  29. signature (Union[str, bytes]): The cryptography signature to check.
  30. Returns:
  31. bool: True if message was signed by the private key associated
  32. with the public key that this object was constructed with.
  33. """
  34. # pylint: disable=missing-raises-doc,redundant-returns-doc
  35. # (pylint doesn't recognize that this is abstract)
  36. raise NotImplementedError("Verify must be implemented")
  37. @six.add_metaclass(abc.ABCMeta)
  38. class Signer(object):
  39. """Abstract base class for cryptographic signers."""
  40. @abc.abstractproperty
  41. def key_id(self):
  42. """Optional[str]: The key ID used to identify this private key."""
  43. raise NotImplementedError("Key id must be implemented")
  44. @abc.abstractmethod
  45. def sign(self, message):
  46. """Signs a message.
  47. Args:
  48. message (Union[str, bytes]): The message to be signed.
  49. Returns:
  50. bytes: The signature of the message.
  51. """
  52. # pylint: disable=missing-raises-doc,redundant-returns-doc
  53. # (pylint doesn't recognize that this is abstract)
  54. raise NotImplementedError("Sign must be implemented")
  55. @six.add_metaclass(abc.ABCMeta)
  56. class FromServiceAccountMixin(object):
  57. """Mix-in to enable factory constructors for a Signer."""
  58. @abc.abstractmethod
  59. def from_string(cls, key, key_id=None):
  60. """Construct an Signer instance from a private key string.
  61. Args:
  62. key (str): Private key as a string.
  63. key_id (str): An optional key id used to identify the private key.
  64. Returns:
  65. google.auth.crypt.Signer: The constructed signer.
  66. Raises:
  67. ValueError: If the key cannot be parsed.
  68. """
  69. raise NotImplementedError("from_string must be implemented")
  70. @classmethod
  71. def from_service_account_info(cls, info):
  72. """Creates a Signer instance instance from a dictionary containing
  73. service account info in Google format.
  74. Args:
  75. info (Mapping[str, str]): The service account info in Google
  76. format.
  77. Returns:
  78. google.auth.crypt.Signer: The constructed signer.
  79. Raises:
  80. ValueError: If the info is not in the expected format.
  81. """
  82. if _JSON_FILE_PRIVATE_KEY not in info:
  83. raise ValueError(
  84. "The private_key field was not found in the service account " "info."
  85. )
  86. return cls.from_string(
  87. info[_JSON_FILE_PRIVATE_KEY], info.get(_JSON_FILE_PRIVATE_KEY_ID)
  88. )
  89. @classmethod
  90. def from_service_account_file(cls, filename):
  91. """Creates a Signer instance from a service account .json file
  92. in Google format.
  93. Args:
  94. filename (str): The path to the service account .json file.
  95. Returns:
  96. google.auth.crypt.Signer: The constructed signer.
  97. """
  98. with io.open(filename, "r", encoding="utf-8") as json_file:
  99. data = json.load(json_file)
  100. return cls.from_service_account_info(data)