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.

util.py 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. ###############################################################################
  2. #
  3. # The MIT License (MIT)
  4. #
  5. # Copyright (c) typedef int GmbH
  6. #
  7. # Permission is hereby granted, free of charge, to any person obtaining a copy
  8. # of this software and associated documentation files (the "Software"), to deal
  9. # in the Software without restriction, including without limitation the rights
  10. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. # copies of the Software, and to permit persons to whom the Software is
  12. # furnished to do so, subject to the following conditions:
  13. #
  14. # The above copyright notice and this permission notice shall be included in
  15. # all copies or substantial portions of the Software.
  16. #
  17. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. # THE SOFTWARE.
  24. #
  25. ###############################################################################
  26. import hashlib
  27. from subprocess import Popen
  28. from typing import Optional
  29. import asyncio
  30. from asyncio import sleep # noqa
  31. from autobahn.wamp.types import TransportDetails
  32. __all = (
  33. 'sleep',
  34. 'peer2str',
  35. 'transport_channel_id',
  36. 'create_transport_details',
  37. )
  38. def transport_channel_id(transport, is_server: bool, channel_id_type: Optional[str] = None) -> bytes:
  39. """
  40. Application-layer user authentication protocols are vulnerable to generic
  41. credential forwarding attacks, where an authentication credential sent by
  42. a client C to a server M may then be used by M to impersonate C at another
  43. server S. To prevent such credential forwarding attacks, modern authentication
  44. protocols rely on channel bindings. For example, WAMP-cryptosign can use
  45. the tls-unique channel identifier provided by the TLS layer to strongly bind
  46. authentication credentials to the underlying channel, so that a credential
  47. received on one TLS channel cannot be forwarded on another.
  48. :param transport: The asyncio TLS transport to extract the TLS channel ID from.
  49. :param is_server: Flag indicating the transport is for a server.
  50. :param channel_id_type: TLS channel ID type, currently only "tls-unique" is supported.
  51. :returns: The TLS channel id (32 bytes).
  52. """
  53. if channel_id_type is None:
  54. return b'\x00' * 32
  55. # ssl.CHANNEL_BINDING_TYPES
  56. if channel_id_type not in ['tls-unique']:
  57. raise Exception("invalid channel ID type {}".format(channel_id_type))
  58. ssl_obj = transport.get_extra_info('ssl_object')
  59. if ssl_obj is None:
  60. raise Exception("TLS transport channel_id for tls-unique requested, but ssl_obj not found on transport")
  61. if not hasattr(ssl_obj, 'get_channel_binding'):
  62. raise Exception("TLS transport channel_id for tls-unique requested, but get_channel_binding not found on ssl_obj")
  63. # https://python.readthedocs.io/en/latest/library/ssl.html#ssl.SSLSocket.get_channel_binding
  64. # https://tools.ietf.org/html/rfc5929.html
  65. tls_finished_msg: bytes = ssl_obj.get_channel_binding(cb_type='tls-unique')
  66. if type(tls_finished_msg) != bytes:
  67. return b'\x00' * 32
  68. else:
  69. m = hashlib.sha256()
  70. m.update(tls_finished_msg)
  71. channel_id = m.digest()
  72. return channel_id
  73. def peer2str(transport: asyncio.transports.BaseTransport) -> str:
  74. # https://docs.python.org/3.9/library/asyncio-protocol.html?highlight=get_extra_info#asyncio.BaseTransport.get_extra_info
  75. # https://docs.python.org/3.9/library/socket.html#socket.socket.getpeername
  76. try:
  77. peer = transport.get_extra_info('peername')
  78. if isinstance(peer, tuple):
  79. ip_ver = 4 if len(peer) == 2 else 6
  80. return "tcp{2}:{0}:{1}".format(peer[0], peer[1], ip_ver)
  81. elif isinstance(peer, str):
  82. return "unix:{0}".format(peer)
  83. else:
  84. return "?:{0}".format(peer)
  85. except:
  86. pass
  87. try:
  88. proc: Popen = transport.get_extra_info('subprocess')
  89. # return 'process:{}'.format(transport.pid)
  90. return 'process:{}'.format(proc.pid)
  91. except:
  92. pass
  93. try:
  94. pipe = transport.get_extra_info('pipe')
  95. return 'pipe:{}'.format(pipe)
  96. except:
  97. pass
  98. # gracefully fallback if we can't map the peer's transport
  99. return 'unknown'
  100. def get_serializers():
  101. from autobahn.wamp import serializer
  102. serializers = ['CBORSerializer', 'MsgPackSerializer', 'UBJSONSerializer', 'JsonSerializer']
  103. serializers = list(filter(lambda x: x, map(lambda s: getattr(serializer, s) if hasattr(serializer, s)
  104. else None, serializers)))
  105. return serializers
  106. def create_transport_details(transport, is_server: bool) -> TransportDetails:
  107. # Internal helper. Base class calls this to create a TransportDetails
  108. peer = peer2str(transport)
  109. # https://docs.python.org/3.9/library/asyncio-protocol.html?highlight=get_extra_info#asyncio.BaseTransport.get_extra_info
  110. is_secure = transport.get_extra_info('peercert', None) is not None
  111. if is_secure:
  112. channel_id = {
  113. 'tls-unique': transport_channel_id(transport, is_server, 'tls-unique'),
  114. }
  115. channel_type = TransportDetails.CHANNEL_TYPE_TLS
  116. peer_cert = None
  117. else:
  118. channel_id = {}
  119. channel_type = TransportDetails.CHANNEL_TYPE_TCP
  120. peer_cert = None
  121. channel_framing = TransportDetails.CHANNEL_FRAMING_WEBSOCKET
  122. return TransportDetails(channel_type=channel_type, channel_framing=channel_framing,
  123. peer=peer, is_server=is_server, is_secure=is_secure,
  124. channel_id=channel_id, peer_cert=peer_cert)