base.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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. from google.auth import exceptions
  19. _JSON_FILE_PRIVATE_KEY = "private_key"
  20. _JSON_FILE_PRIVATE_KEY_ID = "private_key_id"
  21. class Verifier(metaclass=abc.ABCMeta):
  22. """Abstract base class for crytographic signature verifiers."""
  23. @abc.abstractmethod
  24. def verify(self, message, signature):
  25. """Verifies a message against a cryptographic signature.
  26. Args:
  27. message (Union[str, bytes]): The message to verify.
  28. signature (Union[str, bytes]): The cryptography signature to check.
  29. Returns:
  30. bool: True if message was signed by the private key associated
  31. with the public key that this object was constructed with.
  32. """
  33. # pylint: disable=missing-raises-doc,redundant-returns-doc
  34. # (pylint doesn't recognize that this is abstract)
  35. raise NotImplementedError("Verify must be implemented")
  36. class Signer(metaclass=abc.ABCMeta):
  37. """Abstract base class for cryptographic signers."""
  38. @abc.abstractproperty
  39. def key_id(self):
  40. """Optional[str]: The key ID used to identify this private key."""
  41. raise NotImplementedError("Key id must be implemented")
  42. @abc.abstractmethod
  43. def sign(self, message):
  44. """Signs a message.
  45. Args:
  46. message (Union[str, bytes]): The message to be signed.
  47. Returns:
  48. bytes: The signature of the message.
  49. """
  50. # pylint: disable=missing-raises-doc,redundant-returns-doc
  51. # (pylint doesn't recognize that this is abstract)
  52. raise NotImplementedError("Sign must be implemented")
  53. class FromServiceAccountMixin(metaclass=abc.ABCMeta):
  54. """Mix-in to enable factory constructors for a Signer."""
  55. @abc.abstractmethod
  56. def from_string(cls, key, key_id=None):
  57. """Construct an Signer instance from a private key string.
  58. Args:
  59. key (str): Private key as a string.
  60. key_id (str): An optional key id used to identify the private key.
  61. Returns:
  62. google.auth.crypt.Signer: The constructed signer.
  63. Raises:
  64. ValueError: If the key cannot be parsed.
  65. """
  66. raise NotImplementedError("from_string must be implemented")
  67. @classmethod
  68. def from_service_account_info(cls, info):
  69. """Creates a Signer instance instance from a dictionary containing
  70. service account info in Google format.
  71. Args:
  72. info (Mapping[str, str]): The service account info in Google
  73. format.
  74. Returns:
  75. google.auth.crypt.Signer: The constructed signer.
  76. Raises:
  77. ValueError: If the info is not in the expected format.
  78. """
  79. if _JSON_FILE_PRIVATE_KEY not in info:
  80. raise exceptions.MalformedError(
  81. "The private_key field was not found in the service account " "info."
  82. )
  83. return cls.from_string(
  84. info[_JSON_FILE_PRIVATE_KEY], info.get(_JSON_FILE_PRIVATE_KEY_ID)
  85. )
  86. @classmethod
  87. def from_service_account_file(cls, filename):
  88. """Creates a Signer instance from a service account .json file
  89. in Google format.
  90. Args:
  91. filename (str): The path to the service account .json file.
  92. Returns:
  93. google.auth.crypt.Signer: The constructed signer.
  94. """
  95. with io.open(filename, "r", encoding="utf-8") as json_file:
  96. data = json.load(json_file)
  97. return cls.from_service_account_info(data)