Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

strcred.py 8.1KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. # -*- test-case-name: twisted.cred.test.test_strcred -*-
  2. #
  3. # Copyright (c) Twisted Matrix Laboratories.
  4. # See LICENSE for details.
  5. #
  6. """
  7. Support for resolving command-line strings that represent different
  8. checkers available to cred.
  9. Examples:
  10. - passwd:/etc/passwd
  11. - memory:admin:asdf:user:lkj
  12. - unix
  13. """
  14. import sys
  15. from typing import Optional, Sequence, Type
  16. from zope.interface import Attribute, Interface
  17. from twisted.plugin import getPlugins
  18. from twisted.python import usage
  19. class ICheckerFactory(Interface):
  20. """
  21. A factory for objects which provide
  22. L{twisted.cred.checkers.ICredentialsChecker}.
  23. It's implemented by twistd plugins creating checkers.
  24. """
  25. authType = Attribute("A tag that identifies the authentication method.")
  26. authHelp = Attribute(
  27. "A detailed (potentially multi-line) description of precisely "
  28. "what functionality this CheckerFactory provides."
  29. )
  30. argStringFormat = Attribute(
  31. "A short (one-line) description of the argument string format."
  32. )
  33. credentialInterfaces = Attribute(
  34. "A list of credentials interfaces that this factory will support."
  35. )
  36. def generateChecker(argstring):
  37. """
  38. Return an L{twisted.cred.checkers.ICredentialsChecker} provider using the supplied
  39. argument string.
  40. """
  41. class StrcredException(Exception):
  42. """
  43. Base exception class for strcred.
  44. """
  45. class InvalidAuthType(StrcredException):
  46. """
  47. Raised when a user provides an invalid identifier for the
  48. authentication plugin (known as the authType).
  49. """
  50. class InvalidAuthArgumentString(StrcredException):
  51. """
  52. Raised by an authentication plugin when the argument string
  53. provided is formatted incorrectly.
  54. """
  55. class UnsupportedInterfaces(StrcredException):
  56. """
  57. Raised when an application is given a checker to use that does not
  58. provide any of the application's supported credentials interfaces.
  59. """
  60. # This will be used to warn the users whenever they view help for an
  61. # authType that is not supported by the application.
  62. notSupportedWarning = "WARNING: This authType is not supported by " "this application."
  63. def findCheckerFactories():
  64. """
  65. Find all objects that implement L{ICheckerFactory}.
  66. """
  67. return getPlugins(ICheckerFactory)
  68. def findCheckerFactory(authType):
  69. """
  70. Find the first checker factory that supports the given authType.
  71. """
  72. for factory in findCheckerFactories():
  73. if factory.authType == authType:
  74. return factory
  75. raise InvalidAuthType(authType)
  76. def makeChecker(description):
  77. """
  78. Returns an L{twisted.cred.checkers.ICredentialsChecker} based on the
  79. contents of a descriptive string. Similar to
  80. L{twisted.application.strports}.
  81. """
  82. if ":" in description:
  83. authType, argstring = description.split(":", 1)
  84. else:
  85. authType = description
  86. argstring = ""
  87. return findCheckerFactory(authType).generateChecker(argstring)
  88. class AuthOptionMixin:
  89. """
  90. Defines helper methods that can be added on to any
  91. L{usage.Options} subclass that needs authentication.
  92. This mixin implements three new options methods:
  93. The opt_auth method (--auth) will write two new values to the
  94. 'self' dictionary: C{credInterfaces} (a dict of lists) and
  95. C{credCheckers} (a list).
  96. The opt_help_auth method (--help-auth) will search for all
  97. available checker plugins and list them for the user; it will exit
  98. when finished.
  99. The opt_help_auth_type method (--help-auth-type) will display
  100. detailed help for a particular checker plugin.
  101. @cvar supportedInterfaces: An iterable object that returns
  102. credential interfaces which this application is able to support.
  103. @cvar authOutput: A writeable object to which this options class
  104. will send all help-related output. Default: L{sys.stdout}
  105. """
  106. supportedInterfaces: Optional[Sequence[Type[Interface]]] = None
  107. authOutput = sys.stdout
  108. def supportsInterface(self, interface):
  109. """
  110. Returns whether a particular credentials interface is supported.
  111. """
  112. return self.supportedInterfaces is None or interface in self.supportedInterfaces
  113. def supportsCheckerFactory(self, factory):
  114. """
  115. Returns whether a checker factory will provide at least one of
  116. the credentials interfaces that we care about.
  117. """
  118. for interface in factory.credentialInterfaces:
  119. if self.supportsInterface(interface):
  120. return True
  121. return False
  122. def addChecker(self, checker):
  123. """
  124. Supply a supplied credentials checker to the Options class.
  125. """
  126. # First figure out which interfaces we're willing to support.
  127. supported = []
  128. if self.supportedInterfaces is None:
  129. supported = checker.credentialInterfaces
  130. else:
  131. for interface in checker.credentialInterfaces:
  132. if self.supportsInterface(interface):
  133. supported.append(interface)
  134. if not supported:
  135. raise UnsupportedInterfaces(checker.credentialInterfaces)
  136. # If we get this far, then we know we can use this checker.
  137. if "credInterfaces" not in self:
  138. self["credInterfaces"] = {}
  139. if "credCheckers" not in self:
  140. self["credCheckers"] = []
  141. self["credCheckers"].append(checker)
  142. for interface in supported:
  143. self["credInterfaces"].setdefault(interface, []).append(checker)
  144. def opt_auth(self, description):
  145. """
  146. Specify an authentication method for the server.
  147. """
  148. try:
  149. self.addChecker(makeChecker(description))
  150. except UnsupportedInterfaces as e:
  151. raise usage.UsageError("Auth plugin not supported: %s" % e.args[0])
  152. except InvalidAuthType as e:
  153. raise usage.UsageError("Auth plugin not recognized: %s" % e.args[0])
  154. except Exception as e:
  155. raise usage.UsageError("Unexpected error: %s" % e)
  156. def _checkerFactoriesForOptHelpAuth(self):
  157. """
  158. Return a list of which authTypes will be displayed by --help-auth.
  159. This makes it a lot easier to test this module.
  160. """
  161. for factory in findCheckerFactories():
  162. for interface in factory.credentialInterfaces:
  163. if self.supportsInterface(interface):
  164. yield factory
  165. break
  166. def opt_help_auth(self):
  167. """
  168. Show all authentication methods available.
  169. """
  170. self.authOutput.write("Usage: --auth AuthType[:ArgString]\n")
  171. self.authOutput.write("For detailed help: --help-auth-type AuthType\n")
  172. self.authOutput.write("\n")
  173. # Figure out the right width for our columns
  174. firstLength = 0
  175. for factory in self._checkerFactoriesForOptHelpAuth():
  176. if len(factory.authType) > firstLength:
  177. firstLength = len(factory.authType)
  178. formatString = " %%-%is\t%%s\n" % firstLength
  179. self.authOutput.write(formatString % ("AuthType", "ArgString format"))
  180. self.authOutput.write(formatString % ("========", "================"))
  181. for factory in self._checkerFactoriesForOptHelpAuth():
  182. self.authOutput.write(
  183. formatString % (factory.authType, factory.argStringFormat)
  184. )
  185. self.authOutput.write("\n")
  186. raise SystemExit(0)
  187. def opt_help_auth_type(self, authType):
  188. """
  189. Show help for a particular authentication type.
  190. """
  191. try:
  192. cf = findCheckerFactory(authType)
  193. except InvalidAuthType:
  194. raise usage.UsageError("Invalid auth type: %s" % authType)
  195. self.authOutput.write("Usage: --auth %s[:ArgString]\n" % authType)
  196. self.authOutput.write("ArgString format: %s\n" % cf.argStringFormat)
  197. self.authOutput.write("\n")
  198. for line in cf.authHelp.strip().splitlines():
  199. self.authOutput.write(" %s\n" % line.rstrip())
  200. self.authOutput.write("\n")
  201. if not self.supportsCheckerFactory(cf):
  202. self.authOutput.write(" %s\n" % notSupportedWarning)
  203. self.authOutput.write("\n")
  204. raise SystemExit(0)