Example #1
0
    def onAuthenticate(self, signature, extra):
        """
        Callback fired when a client responds to an authentication CHALLENGE.
        """
        self.log.debug("onAuthenticate: {signature} {extra}",
                       signature=signature,
                       extra=extra)

        # if there is a pending auth, check the challenge response. The specifics
        # of how to check depend on the authentication method
        if self._pending_auth:

            # WAMP-Ticket, WAMP-CRA, WAMP-Cryptosign
            if isinstance(self._pending_auth, PendingAuthTicket) or \
               isinstance(self._pending_auth, PendingAuthWampCra) or \
               isinstance(self._pending_auth, PendingAuthCryptosign):
                return self._pending_auth.authenticate(signature)

            # should not arrive here: logic error
            else:
                self.log.warn(
                    'unexpected pending authentication {pending_auth}',
                    pending_auth=self._pending_auth)
                return types.Deny(
                    message=u'internal error: unexpected pending authentication'
                )

        # should not arrive here: client misbehaving!
        else:
            return types.Deny(message=u'no pending authentication')
Example #2
0
    def onAuthenticate(self, signature, extra):
        """
        Callback fired when a client responds to an authentication challenge.
        """
        print("onAuthenticate: {} {}".format(signature, extra))

        # if there is a pending auth, and the signature provided by client matches ..
        if self._pending_auth:

            if signature == self._pending_auth.signature:

                # accept the client
                return types.Accept(
                    authid=self._pending_auth.authid,
                    authrole=self._pending_auth.authrole,
                    authmethod=self._pending_auth.authmethod,
                    authprovider=self._pending_auth.authprovider)
            else:

                # deny client
                return types.Deny(message=u"signature is invalid")
        else:

            # deny client
            return types.Deny(message=u"no pending authentication")
Example #3
0
                def done(res):
                    res = json.loads(res)
                    try:
                        if res['status'] == 'okay':

                            # awesome: Mozilla Persona successfully authenticated the user
                            self._transport._authid = res['email']
                            self._transport._authrole = self._pending_auth.role
                            self._transport._authmethod = 'mozilla_persona'

                            log.msg("Authenticated user {} with role {}".format(self._transport._authid, self._transport._authrole))
                            dres.callback(types.Accept(authid=self._transport._authid, authrole=self._transport._authrole, authmethod=self._transport._authmethod))

                            # remember the user's auth info (this marks the cookie as authenticated)
                            if self._transport._cbtid and self._transport.factory._cookiestore:
                                cs = self._transport.factory._cookiestore
                                cs.setAuth(self._transport._cbtid, self._transport._authid, self._transport._authrole, self._transport._authmethod)

                                # kick all sessions using same cookie (but not _this_ connection)
                                if True:
                                    for proto in cs.getProtos(self._transport._cbtid):
                                        if proto and proto != self._transport:
                                            try:
                                                proto.close()
                                            except Exception as e:
                                                pass
                        else:
                            log.msg("Authentication failed!")
                            log.msg(res)
                            dres.callback(types.Deny(reason="wamp.error.authorization_failed", message=res.get("reason", None)))
                    except Exception as e:
                        log.msg("internal error during authentication verification: {}".format(e))
                        dres.callback(types.Deny(reason="wamp.error.internal_error", message=str(e)))
Example #4
0
 def _marshal_dynamic_authenticator_error(self, err):
     if isinstance(err.value, ApplicationError):
         # forward the inner error URI and message (or coerce the first args item to str)
         return types.Deny(err.value.error, u'{}'.format(err.value.args[0]))
     else:
         # wrap the error
         error = ApplicationError.AUTHENTICATION_FAILED
         message = u'dynamic authenticator failed: {}'.format(err.value)
         return types.Deny(error, message)
Example #5
0
    def authenticate(self, signature):

        # WAMP-Ticket "static"
        if self._authprovider == 'static':

            # when doing WAMP-Ticket from static configuration, the ticket we
            # expect was previously stored in self._signature
            if signature == self._signature:
                # ticket was valid: accept the client
                self.log.debug("WAMP-Ticket: ticket was valid!")
                return self._accept()
            else:
                # ticket was invalid: deny client
                self.log.debug(
                    'WAMP-Ticket (static): expected ticket "{expected}"" ({expected_type}), but got "{sig}" ({sig_type})',
                    expected=self._signature,
                    expected_type=type(self._signature),
                    sig=signature,
                    sig_type=type(signature),
                )
                return types.Deny(
                    message=
                    "ticket in static WAMP-Ticket authentication is invalid")

        # WAMP-Ticket "dynamic"
        elif self._authprovider == 'dynamic':

            self._session_details['ticket'] = signature
            d = self._authenticator_session.call(self._authenticator,
                                                 self._realm, self._authid,
                                                 self._session_details)

            def on_authenticate_ok(principal):
                # backwards compatibility: dynamic ticket authenticator
                # was expected to return a role directly
                if isinstance(principal, str):
                    principal = {'role': principal}

                error = self._assign_principal(principal)
                if error:
                    return error

                return self._accept()

            def on_authenticate_error(err):
                return self._marshal_dynamic_authenticator_error(err)

            d.addCallbacks(on_authenticate_ok, on_authenticate_error)

            return d

        else:
            # should not arrive here, as config errors should be caught earlier
            return types.Deny(
                message=
                'invalid authentication configuration (authentication type "{}" is unknown)'
                .format(self._config['type']))
Example #6
0
    def hello(self, realm, details):

        # remember the realm the client requested to join (if any)
        self._realm = realm

        # remember the authid the client wants to identify as (if any)
        self._authid = details.authid

        # use static principal database from configuration
        if self._config['type'] == 'static':

            self._authprovider = 'static'

            if self._authid in self._config.get('principals', {}):

                principal = self._config['principals'][self._authid]
                principal['extra'] = details.authextra

                error = self._assign_principal(principal)
                if error:
                    return error

                # now set set signature as expected for WAMP-Ticket
                self._signature = principal['ticket']

                return types.Challenge(self._authmethod)
            else:
                return types.Deny(
                    message='no principal with authid "{}" exists'.format(
                        self._authid))

        # use configured procedure to dynamically get a ticket for the principal
        elif self._config['type'] == 'dynamic':

            self._authprovider = 'dynamic'

            init_d = as_future(self._init_dynamic_authenticator)

            def init(result):
                if result:
                    return result

                self._session_details[
                    'authmethod'] = self._authmethod  # from AUTHMETHOD, via base
                self._session_details['authextra'] = details.authextra

                return types.Challenge(self._authmethod)

            init_d.addBoth(init)
            return init_d

        else:
            # should not arrive here, as config errors should be caught earlier
            return types.Deny(
                message=
                'invalid authentication configuration (authentication type "{}" is unknown)'
                .format(self._config['type']))
Example #7
0
    def hello(self, realm, details):
        self.log.debug('{klass}.hello(realm={realm}, details={details}) ...',
                       klass=self.__class__.__name__,
                       realm=realm,
                       details=details)
        if not details.authextra:
            return types.Deny(message='missing required details.authextra')
        for attr in ['proxy_authid', 'proxy_authrole', 'proxy_realm']:
            if attr not in details.authextra:
                return types.Deny(
                    message='missing required attribute {} in details.authextra'
                    .format(attr))

        if details.authrole is None:
            details.authrole = details.authextra.get('proxy_authrole', None)
        if details.authid is None:
            details.authid = details.authextra.get('proxy_authid', None)

        # with authentictors of type "*-proxy", the principal returned in authenticating the
        # incoming backend connection is ignored ..
        f = super(PendingAuthCryptosignProxy, self).hello(realm, details)

        def assign(res):
            """
            .. and the incoming backend connection from the proxy frontend is authenticated as the principal
            the frontend proxy has _already_ authenticated the actual client (before even connecting and
            authenticating to the backend here)
            """
            if isinstance(res, types.Deny):
                return res

            principal = {}
            principal['realm'] = details.authextra['proxy_realm']
            principal['authid'] = details.authextra['proxy_authid']
            principal['role'] = details.authextra['proxy_authrole']
            principal['extra'] = details.authextra.get('proxy_authextra', None)
            self._assign_principal(principal)

            self.log.debug(
                '{klass}.hello(realm={realm}, details={details}) -> principal={principal}',
                klass=self.__class__.__name__,
                realm=realm,
                details=details,
                principal=principal,
            )
            return self._accept()

        def error(f):
            return types.Deny("Internal error: {}".format(f))

        txaio.add_callbacks(f, assign, error)
        return f
Example #8
0
    def _init_dynamic_authenticator(self):
        self._authenticator = self._config['authenticator']

        authenticator_realm = None
        if u'authenticator-realm' in self._config:
            authenticator_realm = self._config[u'authenticator-realm']
            if authenticator_realm not in self._router_factory:
                return types.Deny(ApplicationError.NO_SUCH_REALM, message=u"explicit realm <{}> configured for dynamic authenticator does not exist".format(authenticator_realm))
        else:
            if not self._realm:
                return types.Deny(ApplicationError.NO_SUCH_REALM, message=u"client did not specify a realm to join (and no explicit realm was configured for dynamic authenticator)")
            authenticator_realm = self._realm

        self._authenticator_session = self._router_factory.get(authenticator_realm)._realm.session
Example #9
0
    def onAuthenticate(self, router_session, signature, extra):
        try:
            challenge = router_session.challenge
            if challenge == None:
                return
            if router_session.challenge.get("authmethod") != u"wampcra":
                return
            for field in ["authid", "authrole", "authmethod", "authprovider"]:
                if field not in challenge:
                    # Challenge not in expected format. It was probably
                    #   created by another plugin.
                    return

            if not router_session.challenge or not router_session.signature:
                log("Failed wampcra login for %s." % challenge["authid"])
                return types.Deny(message=u"No pending authentication.")

            if len(signature) != len(router_session.signature):
                log("Failed wampcra login for %s." % challenge["authid"])
                return types.Deny(message=u"Invalid signature.")

            success = True

            # Check each character to prevent HMAC timing attacks. This is
            #   really not an issue since each challenge gets a new nonce,
            #   but better safe than sorry.
            for i in range(len(router_session.signature)):
                if signature[i] != router_session.signature[i]:
                    success = False

            # Reject the user if we did not actually find them in the database.
            if not router_session.exists:
                log("User %s not found." % challenge["authid"])
                success = False

            if success:
                log("Successful wampcra login for %s." % challenge["authid"])
                return types.Accept(authid=challenge["authid"],
                                    authrole=challenge["authrole"],
                                    authmethod=challenge["authmethod"],
                                    authprovider=challenge["authprovider"])

            log("Failed wampcra login for %s." % challenge["authid"])
            return types.Deny(message=u"Invalid signature.")

        except:
            # let another plugin handle this
            return
Example #10
0
    def onAuthenticate(self, router_session, signature, extra):
        if not hasattr(router_session, "totp"):
            return

        username = router_session.challenge["authid"].encode("utf8")
        totp = router_session.totp
        if totp:
            if "otp" not in extra:
                log("TOTP parameter is missing for %s." % username)
                returnValue(types.Deny(message=u"Missing TOTP."))
            success = yield self.administrator.proxy.check_totp(
                username, extra["otp"].encode("utf-8"))
            if not success:
                log("TOTP parameter is invalid for %s." % username)
                returnValue(types.Deny(message=u"Invalid TOTP."))
            log("Successfully verified TOTP for %s." % username)
Example #11
0
 def error(err):
     self.log.info("Authentication request failed: {}".format(
         err.value))
     dres.callback(
         types.Deny(
             reason="wamp.error.authorization_request_failed",
             message=str(err.value)))
Example #12
0
    def hello(self, realm, details):
        self.log.debug('{klass}.hello(realm={realm}, details={details}) ...',
                       klass=self.__class__.__name__,
                       realm=realm,
                       details=details)
        extra = details.authextra or {}

        for attr in ['proxy_authid', 'proxy_authrole', 'proxy_realm']:
            if attr not in extra:
                return types.Deny(
                    message='missing required attribute {}'.format(attr))

        realm = extra['proxy_realm']
        details.authid = extra['proxy_authid']
        details.authrole = extra['proxy_authrole']
        details.authextra = extra.get('proxy_authextra', None)

        self.log.debug(
            '{klass}.hello(realm={realm}, details={details}) -> realm={realm}, authid={authid}, authrole={authrole}, authextra={authextra}',
            klass=self.__class__.__name__,
            realm=realm,
            details=details,
            authid=details.authid,
            authrole=details.authrole,
            authextra=details.authextra)

        return super(PendingAuthCryptosignProxy, self).hello(realm, details)
Example #13
0
    def onHello(self, realm, details):
        """
      Callback fired when client wants to attach session.
      """
        print("onHello: {} {}".format(realm, details))

        try:

            self._pending_auth = None

            if details.authmethods:
                for authmethod in details.authmethods:
                    if authmethod == u"totp":

                        ## lookup user in user DB
                        secret, authrole = yield self.factory.userdb.get(
                            details.authid)

                        ## if user found ..
                        if secret:

                            ## setup pending auth
                            self._pending_auth = PendingAuth(
                                secret, details.authid, authrole, authmethod,
                                "userdb")

                            defer.returnValue(types.Challenge('totp'))

            ## deny client
            defer.returnValue(types.Deny())
        except Exception as e:
            print e
Example #14
0
    def hello(self, realm, details):
        self.log.debug('{func}(realm="{realm}", details={details})',
                       func=hltype(self.hello),
                       realm=hlval(realm),
                       details=details)
        extra = details.authextra or {}

        for attr in ['proxy_authid', 'proxy_authrole', 'proxy_realm']:
            if attr not in extra:
                return types.Deny(message='missing required attribute {}'.format(attr))

        realm = extra['proxy_realm']
        details.authid = extra['proxy_authid']
        details.authrole = extra['proxy_authrole']
        details.authextra = extra.get('proxy_authextra', None)

        # remember the realm the client requested to join (if any)
        self._realm = realm
        self._authid = details.authid
        self._session_details['authmethod'] = 'anonymous'
        self._session_details['authextra'] = details.authextra
        self._authprovider = 'static'

        # FIXME: if cookie tracking is enabled, set authid to cookie value
        # self._authid = self._transport._cbtid

        principal = {'realm': realm, 'authid': details.authid, 'role': details.authrole, 'extra': details.authextra}

        error = self._assign_principal(principal)
        if error:
            return error

        return self._accept()
Example #15
0
    def onAuthenticate(self, router_session, signature, extra):
        try:
            challenge = router_session.challenge
            authid = challenge["authid"]
            if challenge == None:
                return
            if router_session.challenge.get("authmethod") != u"cookie":
                return
            for field in ["authrole", "authmethod", "authprovider"]:
                if field not in challenge:
                    # Challenge not in expected format. It was probably
                    #   created by another plugin.
                    return
        except Exception as e:
            # let another plugin handle this
            return

        cookie = self.cookies.get(authid)
        if cookie != signature:
            log("Failed cookie login for %s." % challenge["authid"])
            return types.Deny(message=u"Invalid cookie.")

        log("Successful cookie login for %s." % challenge["authid"])
        return types.Accept(authid=challenge["authid"],
                            authrole=challenge["authrole"],
                            authmethod=challenge["authmethod"],
                            authprovider=challenge["authprovider"])
Example #16
0
    def _init_function_authenticator(self):
        self.log.debug('{klass}._init_function_authenticator', klass=self.__class__.__name__)

        # import the module for the function
        create_fqn = self._config['create']
        if '.' not in create_fqn:
            return types.Deny(
                ApplicationError.NO_SUCH_PROCEDURE,
                "'function' authenticator has no module: '{}'".format(create_fqn)
            )

        if self._config.get('expose_controller', None):
            from crossbar.worker.controller import WorkerController
            if not isinstance(self._realm_container, WorkerController):
                excp = Exception(
                    "Internal Error: Our container '{}' is not a WorkerController".format(
                        self._realm_container,
                    )
                )
                self.log.failure('{klass} could not expose controller',
                                 klass=self.__class__.__name__, failure=excp)
                raise excp
            controller = self._realm_container
        else:
            controller = None

        create_d = txaio.as_future(_authenticator_for_name, self._config, controller=controller)

        def got_authenticator(authenticator):
            self._authenticator = authenticator
        create_d.addCallback(got_authenticator)
        return create_d
    def hello(self, realm, details):

        # remember the realm the client requested to join (if any)
        self._realm = realm

        # remember the authid the client wants to identify as (if any)
        self._authid = details.authid

        # use static principal database from configuration
        if self._config[u'type'] == u'static':

            self._authprovider = u'static'

            if self._authid in self._config.get(u'principals', {}):

                principal = self._config[u'principals'][self._authid]

                error = self._assign_principal(principal)
                if error:
                    return error

                # now set set signature as expected for WAMP-Ticket
                self._signature = principal[u'ticket']

                return types.Challenge(self._authmethod)
            else:
                return types.Deny(
                    message=u'no principal with authid "{}" exists'.format(
                        self._authid))

        # use configured procedure to dynamically get a ticket for the principal
        elif self._config[u'type'] == u'dynamic':

            self._authprovider = u'dynamic'

            error = self._init_dynamic_authenticator()
            if error:
                return error

            return types.Challenge(self._authmethod)

        else:
            # should not arrive here, as config errors should be caught earlier
            return types.Deny(
                message=
                u'invalid authentication configuration (authentication type "{}" is unknown)'
                .format(self._config['type']))
Example #18
0
    def hello(self, realm, details):

        # remember the realm the client requested to join (if any)
        self._realm = realm

        # remember the authid the client wants to identify as (if any)
        self._authid = details.authid

        # WAMP-Ticket "static"
        if self._config[u'type'] == u'static':

            self._authprovider = u'static'
            self._authid = util.generate_serial_number()

            # FIXME: if cookie tracking is enabled, set authid to cookie value
            # self._authid = self._transport._cbtid

            principal = self._config

            error = self._assign_principal(principal)
            if error:
                return error

            return self._accept()

        # WAMP-Ticket "dynamic"
        elif self._config[u'type'] == u'dynamic':

            self._authprovider = u'dynamic'
            self._authid = util.generate_serial_number()

            error = self._init_dynamic_authenticator()
            if error:
                return error

            d = self._authenticator_session.call(self._authenticator,
                                                 self._realm, self._authid,
                                                 self._session_details)

            def on_authenticate_ok(principal):
                error = self._assign_principal(principal)
                if error:
                    return error

                return self._accept()

            def on_authenticate_error(err):
                return self._marshal_dynamic_authenticator_error(err)

            d.addCallbacks(on_authenticate_ok, on_authenticate_error)

            return d

        else:
            # should not arrive here, as config errors should be caught earlier
            return types.Deny(
                message=
                u'invalid authentication configuration (authentication type "{}" is unknown)'
                .format(self._config['type']))
Example #19
0
 def on_success(response):
     content = json.loads(response)
     if content.get('success'):
         username = content.get('username')
         if username:
             return types.Accept(content['username'])
     log.msg('Rejected login: %s' % (content, ))
     return types.Deny()
Example #20
0
    def authenticate(self, signature):

        if signature == self._signature:
            # signature was valid: accept the client
            return self._accept()
        else:
            # signature was invalid: deny the client
            return types.Deny(message="WAMP-CRA signature is invalid")
Example #21
0
 def on_authenticate_error(err):
     self.log.info('{klass}.hello(realm="{realm}", details={details}) -> on_authenticate_error(err={err})',
                   klass=self.__class__.__name__, realm=realm, details=details, err=err)
     try:
         return self._marshal_dynamic_authenticator_error(err)
     except Exception as e:
         error = ApplicationError.AUTHENTICATION_FAILED
         message = 'marshalling of function-based authenticator error return failed: {}'.format(e)
         self.log.warn('{klass}.hello.on_authenticate_error() - {msg}', msg=message)
         return types.Deny(error, message)
Example #22
0
                    def on_authenticate_error(err):
                        error = None
                        message = "dynamic WAMP-Ticket credential getter failed: {}".format(err)

                        if isinstance(err.value, ApplicationError):
                            error = err.value.error
                            if err.value.args and len(err.value.args):
                                message = err.value.args[0]

                        return types.Deny(error, message)
Example #23
0
    def _assign_principal(self, principal):
        # allow to override realm request, redirect realm or set default realm
        if u'realm' in principal:
            self._realm = principal['realm']

        if not self._realm:
            return types.Deny(ApplicationError.NO_SUCH_REALM,
                              message=u'no realm assigned')

        # check if effective realm exists on router
        if self._realm not in self._router_factory:
            return types.Deny(
                ApplicationError.NO_SUCH_REALM,
                message=u'no realm "{}" exists on this router'.format(
                    self._realm))

        # effective authrole
        if u'role' in principal:
            self._authrole = principal[u'role']
        elif u'default-role' in self._config:
            self._authrole = self._config[u'default-role']
        else:
            return types.Deny(ApplicationError.NO_SUCH_ROLE,
                              message=u'no authrole assigned')

        # check if role exists on realm
        if not self._router_factory[self._realm].has_role(self._authrole):
            return types.Deny(ApplicationError.NO_SUCH_ROLE,
                              message=u'realm "{}" has no role "{}"'.format(
                                  self._realm, self._authrole))

        # allow overriding effectively assigned authid
        if u'authid' in principal:
            self._authid = principal[u'authid']

        if not self._authid:
            return types.Deny(ApplicationError.NO_SUCH_PRINCIPAL,
                              message=u'no authid assigned')

        # allow forwarding of application-specific "welcome data"
        if u'extra' in principal:
            self._authextra = principal[u'extra']
    def onHello(self, realm, details):
        print("On hello: {}".format(details))
        if u"exodoc-ticket" not in details.authmethods:
            return types.Deny(
                u"wamp.error.not_authorized",
                message=u"Only 'exodoc-ticket' supported as authmethods")
        if not details.authid.startswith("good-ticket-"):
            return types.Deny(u"wamp.error.not_authorized",
                              message=u"Bad credential")

        self._authid = details.authid[len("good-ticket-"):]
        self._authmethod = u"exodoc-ticket"
        self._authrole = u"chatter"
        self._authprovider = u"redis-token"
        return types.Accept(
            authid=self._authid,
            authrole=self._authrole,
            authmethod=self._authmethod,
            authprovider=self._authprovider,
        )
Example #25
0
                                    def on_authenticate_error(err):

                                        error = None
                                        message = "dynamic WAMP-CRA credential getter failed: {}".format(err)

                                        if isinstance(err.value, ApplicationError):
                                            error = err.value.error
                                            if err.value.args and len(err.value.args):
                                                message = str(err.value.args[0])  # exception does not need to contain a string

                                        return types.Deny(error, message)
Example #26
0
    def authenticate(self, signature):
        # signatures in WAMP are strings, hence we roundtrip Hex
        signature = binascii.a2b_hex(signature)

        signed = SignedMessage(signature)
        try:
            # now verify the signed message versus the client public key
            self._verify_key.verify(signed)

            # signature was valid: accept the client
            return self._accept()

        except BadSignatureError:

            # signature was invalid: deny the client
            return types.Deny(message=u"invalid signature")

        except Exception as e:

            # should not arrive here .. but who knows
            return types.Deny(message=u"internal error: {}".format(e))
Example #27
0
    def _init_dynamic_authenticator(self):
        self._authenticator = self._config['authenticator']

        authenticator_realm = None
        if 'authenticator-realm' in self._config:
            authenticator_realm = self._config['authenticator-realm']
            if not self._realm_container.has_realm(authenticator_realm):
                return types.Deny(
                    ApplicationError.NO_SUCH_REALM,
                    message=
                    "explicit realm <{}> configured for dynamic authenticator does not exist"
                    .format(authenticator_realm))
        else:
            if not self._realm:
                return types.Deny(
                    ApplicationError.NO_SUCH_REALM,
                    message=
                    "client did not specify a realm to join (and no explicit realm was configured for dynamic authenticator)"
                )
            authenticator_realm = self._realm

        self._authenticator_session = self._realm_container.get_service_session(
            authenticator_realm)
Example #28
0
    def authenticate(self, signed_message):
        """
        Verify the signed message sent by the client.

        :param signed_message: the base64-encoded result "ClientProof"
            from the SCRAM protocol
        """

        channel_binding = ""
        client_nonce = base64.b64encode(self._client_nonce).decode('ascii')
        server_nonce = base64.b64encode(self._server_nonce).decode('ascii')
        salt = base64.b64encode(self._salt).decode('ascii')
        auth_message = (
            "{client_first_bare},{server_first},{client_final_no_proof}".
            format(
                client_first_bare="n={},r={}".format(saslprep(self._authid),
                                                     client_nonce),
                server_first="r={},s={},i={}".format(server_nonce, salt,
                                                     self._iterations),
                client_final_no_proof="c={},r={}".format(
                    channel_binding, server_nonce),
            ))

        received_client_proof = base64.b64decode(signed_message)

        client_signature = hmac.new(self._stored_key,
                                    auth_message.encode('ascii'),
                                    hashlib.sha256).digest()
        recovered_client_key = util.xor(client_signature,
                                        received_client_proof)
        recovered_stored_key = hashlib.new('sha256',
                                           recovered_client_key).digest()

        # if we adjust self._authextra before _accept() it gets sent
        # back to the client
        server_signature = hmac.new(self._server_key,
                                    auth_message.encode('ascii'),
                                    hashlib.sha256).digest()
        if self._authextra is None:
            self._authextra = {}
        self._authextra['scram_server_signature'] = base64.b64encode(
            server_signature).decode('ascii')

        if hmac.compare_digest(recovered_stored_key, self._stored_key):
            return self._accept()

        self.log.error("SCRAM authentication failed for '{authid}'",
                       authid=self._authid)
        return types.Deny(message='SCRAM authentication failed')
Example #29
0
    def onHello(self, realm, details):
        """
        Callback fired when client wants to attach session.
        """
        print("MyRouterSession.onHello: {} {}".format(realm, details))

        for authmethod in details.authmethods:
            if authmethod == u"cookie" and self._transport._authenticated is not None:
                # already authenticated via Cookie on transport
                return types.Accept(authid=self._transport._authenticated, authrole="user", authmethod="cookie")
            elif authmethod == u"mozilla-persona":
                # not yet authenticated: send challenge
                return types.Challenge("mozilla-persona")

        return types.Deny()
Example #30
0
    def hello(self, realm, details):
        self.log.info('{klass}.hello(realm={realm}, details={details}) ...',
                      klass=self.__class__.__name__,
                      realm=realm,
                      details=details)
        extra = details.authextra or {}

        for attr in ['proxy_authid', 'proxy_authrole', 'proxy_realm']:
            if attr not in extra:
                return types.Deny(
                    message='missing required attribute {}'.format(attr))

        realm = extra['proxy_realm']
        details.authid = extra['proxy_authid']
        details.authrole = extra['proxy_authrole']
        details.authextra = extra.get('proxy_authextra', None)

        self.log.info(
            '{klass}.hello(realm={realm}, details={details}) -> realm={realm}, authid={authid}, authrole={authrole}, authextra={authextra}',
            klass=self.__class__.__name__,
            realm=realm,
            details=details,
            authid=details.authid,
            authrole=details.authrole,
            authextra=details.authextra)

        # remember the realm the client requested to join (if any)
        self._realm = realm
        self._authid = details.authid
        self._session_details['authmethod'] = 'anonymous'
        self._session_details['authextra'] = details.authextra
        self._authprovider = 'static'

        # FIXME: if cookie tracking is enabled, set authid to cookie value
        # self._authid = self._transport._cbtid

        principal = {
            'realm': realm,
            'authid': details.authid,
            'role': details.authrole,
            'extra': details.authextra
        }

        error = self._assign_principal(principal)
        if error:
            return error

        return self._accept()