예제 #1
0
                                    def on_authenticate_ok(user):

                                        # the authid the session will be authenticated as is from the dynamic
                                        # authenticator response, or when the response doesn't contain an authid,
                                        # from the HELLO message the client sent
                                        #
                                        authid = user.get(
                                            "authid", details.authid)

                                        # construct a pending WAMP-CRA authentication
                                        #
                                        self._pending_auth = PendingAuthWampCra(
                                            details.pending_session, authid,
                                            user['role'], u'dynamic',
                                            user['secret'].encode('utf8'))

                                        # send challenge to client
                                        #
                                        extra = {
                                            u'challenge':
                                            self._pending_auth.challenge
                                        }

                                        # when using salted passwords, provide the client with
                                        # the salt and the PBKDF2 parameters used
                                        #
                                        if 'salt' in user:
                                            extra[u'salt'] = user['salt']
                                            extra[u'iterations'] = user.get(
                                                'iterations', 1000)
                                            extra[u'keylen'] = user.get(
                                                'keylen', 32)

                                        return types.Challenge(
                                            u'wampcra', extra)
예제 #2
0
                                    def on_authenticate_ok(user):

                                        ## construct a pending WAMP-CRA authentication
                                        ##
                                        self._pending_auth = PendingAuthWampCra(
                                            details.pending_session,
                                            details.authid, user['role'],
                                            u'dynamic',
                                            user['secret'].encode('utf8'))

                                        ## send challenge to client
                                        ##
                                        extra = {
                                            u'challenge':
                                            self._pending_auth.challenge
                                        }

                                        ## when using salted passwords, provide the client with
                                        ## the salt and the PBKDF2 parameters used
                                        ##
                                        if 'salt' in user:
                                            extra[u'salt'] = user['salt']
                                            extra[u'iterations'] = user.get(
                                                'iterations', 1000)
                                            extra[u'keylen'] = user.get(
                                                'keylen', 32)

                                        return types.Challenge(
                                            u'wampcra', extra)
예제 #3
0
    def onHello(self, realm, details):

        try:

            # check if the realm the session wants to join actually exists
            #
            if realm not in self._router_factory:
                return types.Deny(
                    ApplicationError.NO_SUCH_REALM,
                    message="no realm '{}' exists on this router".format(
                        realm))

            authmethods = details.authmethods or ["anonymous"]

            # perform authentication
            #
            if self._transport._authid is not None and (
                    self._transport._authmethod == u'trusted'
                    or self._transport._authprovider in authmethods):

                # already authenticated .. e.g. via HTTP Cookie or TLS client-certificate

                # check if role still exists on realm
                #
                allow = self._router_factory[realm].has_role(
                    self._transport._authrole)

                if allow:
                    return types.Accept(
                        authid=self._transport._authid,
                        authrole=self._transport._authrole,
                        authmethod=self._transport._authmethod,
                        authprovider=self._transport._authprovider)
                else:
                    return types.Deny(
                        ApplicationError.NO_SUCH_ROLE,
                        message=
                        "session was previously authenticated (via transport), but role '{}' no longer exists on realm '{}'"
                        .format(self._transport._authrole, realm))

            else:
                # if authentication is enabled on the transport ..
                #
                if "auth" in self._transport_config:

                    # iterate over authentication methods announced by client ..
                    #
                    for authmethod in authmethods:

                        # .. and if the configuration has an entry for the authmethod
                        # announced, process ..
                        if authmethod in self._transport_config["auth"]:

                            # "WAMP-Challenge-Response" authentication
                            #
                            if authmethod == u"wampcra":
                                cfg = self._transport_config['auth']['wampcra']

                                if cfg['type'] == 'static':

                                    if details.authid in cfg.get('users', {}):

                                        user = cfg['users'][details.authid]

                                        # the authid the session will be authenticated as is from the user data, or when
                                        # the user data doesn't contain an authid, from the HELLO message the client sent
                                        #
                                        authid = user.get(
                                            "authid", details.authid)

                                        # construct a pending WAMP-CRA authentication
                                        #
                                        self._pending_auth = PendingAuthWampCra(
                                            details.pending_session, authid,
                                            user['role'], u'static',
                                            user['secret'].encode('utf8'))

                                        # send challenge to client
                                        #
                                        extra = {
                                            u'challenge':
                                            self._pending_auth.challenge
                                        }

                                        # when using salted passwords, provide the client with
                                        # the salt and then PBKDF2 parameters used
                                        #
                                        if 'salt' in user:
                                            extra[u'salt'] = user['salt']
                                            extra[u'iterations'] = user.get(
                                                'iterations', 1000)
                                            extra[u'keylen'] = user.get(
                                                'keylen', 32)

                                        return types.Challenge(
                                            u'wampcra', extra)

                                    else:
                                        return types.Deny(
                                            message=
                                            "no user with authid '{}' in user database"
                                            .format(details.authid))

                                elif cfg['type'] == 'dynamic':

                                    # call the configured dynamic authenticator procedure
                                    # via the router's service session
                                    #
                                    service_session = self._router_factory.get(
                                        realm)._realm.session
                                    session_details = {
                                        # forward transport level details of the WAMP session that
                                        # wishes to authenticate
                                        'transport':
                                        self._transport._transport_info,

                                        # the following WAMP session ID will be assigned to the session
                                        # if (and only if) the subsequent authentication succeeds.
                                        'session': self._pending_session_id
                                    }
                                    d = service_session.call(
                                        cfg['authenticator'], realm,
                                        details.authid, session_details)

                                    def on_authenticate_ok(user):

                                        # the authid the session will be authenticated as is from the dynamic
                                        # authenticator response, or when the response doesn't contain an authid,
                                        # from the HELLO message the client sent
                                        #
                                        authid = user.get(
                                            "authid", details.authid)

                                        # construct a pending WAMP-CRA authentication
                                        #
                                        self._pending_auth = PendingAuthWampCra(
                                            details.pending_session, authid,
                                            user['role'], u'dynamic',
                                            user['secret'].encode('utf8'))

                                        # send challenge to client
                                        #
                                        extra = {
                                            u'challenge':
                                            self._pending_auth.challenge
                                        }

                                        # when using salted passwords, provide the client with
                                        # the salt and the PBKDF2 parameters used
                                        #
                                        if 'salt' in user:
                                            extra[u'salt'] = user['salt']
                                            extra[u'iterations'] = user.get(
                                                'iterations', 1000)
                                            extra[u'keylen'] = user.get(
                                                'keylen', 32)

                                        return types.Challenge(
                                            u'wampcra', extra)

                                    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)

                                    d.addCallbacks(on_authenticate_ok,
                                                   on_authenticate_error)

                                    return d

                                else:

                                    return types.Deny(
                                        message=
                                        "illegal WAMP-CRA authentication config (type '{0}' is unknown)"
                                        .format(cfg['type']))

                            # WAMP-Ticket authentication
                            #
                            elif authmethod == u"ticket":
                                cfg = self._transport_config['auth']['ticket']

                                # use static principal database from configuration
                                #
                                if cfg['type'] == 'static':

                                    if details.authid in cfg.get(
                                            'principals', {}):

                                        principal = cfg['principals'][
                                            details.authid]

                                        # the authid the session will be authenticated as is from the principal data, or when
                                        # the principal data doesn't contain an authid, from the HELLO message the client sent
                                        #
                                        authid = principal.get(
                                            "authid", details.authid)

                                        self._pending_auth = PendingAuthTicket(
                                            realm, authid, principal['role'],
                                            u'static',
                                            principal['ticket'].encode('utf8'))

                                        return types.Challenge(u'ticket')
                                    else:
                                        return types.Deny(
                                            message=
                                            "no principal with authid '{}' in principal database"
                                            .format(details.authid))

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

                                    self._pending_auth = PendingAuthTicket(
                                        realm, details.authid, None,
                                        cfg['authenticator'], None)

                                    return types.Challenge(u'ticket')

                                else:
                                    return types.Deny(
                                        message=
                                        "illegal WAMP-Ticket authentication config (type '{0}' is unknown)"
                                        .format(cfg['type']))

                            # "Mozilla Persona" authentication
                            #
                            elif authmethod == u"mozilla_persona":
                                cfg = self._transport_config['auth'][
                                    'mozilla_persona']

                                audience = cfg.get('audience',
                                                   self._transport._origin)
                                provider = cfg.get(
                                    'provider',
                                    "https://verifier.login.persona.org/verify"
                                )

                                # authrole mapping
                                #
                                authrole = cfg.get('role', 'anonymous')

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

                                # ok, now challenge the client for doing Mozilla Persona auth.
                                #
                                self._pending_auth = PendingAuthPersona(
                                    provider, audience, authrole)
                                return types.Challenge("mozilla-persona")

                            # "Anonymous" authentication
                            #
                            elif authmethod == u"anonymous":
                                cfg = self._transport_config['auth'][
                                    'anonymous']

                                # authrole mapping
                                #
                                authrole = cfg.get('role', 'anonymous')

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

                                # authid generation
                                if self._transport._cbtid:
                                    # if cookie tracking is enabled, set authid to cookie value
                                    authid = self._transport._cbtid
                                else:
                                    # if no cookie tracking, generate a random value for authid
                                    authid = util.newid(24)

                                self._transport._authid = authid
                                self._transport._authrole = authrole
                                self._transport._authmethod = authmethod

                                return types.Accept(
                                    authid=authid,
                                    authrole=authrole,
                                    authmethod=self._transport._authmethod)

                            # "Cookie" authentication
                            #
                            elif authmethod == u"cookie":
                                # the client requested cookie authentication, but there is 1) no cookie set,
                                # or 2) a cookie set, but that cookie wasn't authenticated before using
                                # a different auth method (if it had been, we would never have entered here, since then
                                # auth info would already have been extracted from the transport)
                                # consequently, we skip this auth method and move on to next auth method.
                                pass

                            # Unknown authentication method
                            #
                            else:
                                self.log.info("unknown authmethod '{}'".format(
                                    authmethod))
                                return types.Deny(
                                    message="unknown authentication method {}".
                                    format(authmethod))

                    # if authentication is configured, by default, deny.
                    #
                    return types.Deny(
                        message=
                        "authentication using method '{}' denied by configuration"
                        .format(authmethod))

                else:
                    # if authentication is _not_ configured, by default, allow anyone.
                    #

                    # authid generation
                    if self._transport._cbtid:
                        # if cookie tracking is enabled, set authid to cookie value
                        authid = self._transport._cbtid
                    else:
                        # if no cookie tracking, generate a random value for authid
                        authid = util.newid(24)

                    return types.Accept(authid=authid,
                                        authrole="anonymous",
                                        authmethod="anonymous")

        except Exception as e:
            traceback.print_exc()
            return types.Deny(message="internal error: {}".format(e))
예제 #4
0
    def test_wamp_cra_challenge(self):
        secret = os.urandom(32)
        pend = PendingAuthWampCra(1234, u'authid', u'authrole', None, secret)

        self.assertTrue(isinstance(pend.challenge, six.text_type))
        self.assertTrue(isinstance(pend.signature, six.text_type))
예제 #5
0
    def onHello(self, realm, details):

        try:

            ## check if the realm the session wants to join actually exists
            ##
            if realm not in self._router_factory:
                return types.Deny(
                    ApplicationError.NO_SUCH_REALM,
                    message="no realm '{}' exists on this router".format(
                        realm))

            ## perform authentication
            ##
            if self._transport._authid is not None:

                ## already authenticated .. e.g. via cookie

                ## check if role still exists on realm
                ##
                allow = self._router_factory[realm].has_role(
                    self._transport._authrole)

                if allow:
                    return types.Accept(authid=self._transport._authid,
                                        authrole=self._transport._authrole,
                                        authmethod=self._transport._authmethod,
                                        authprovider='transport')
                else:
                    return types.Deny(
                        ApplicationError.NO_SUCH_ROLE,
                        message=
                        "session was previously authenticated (via transport), but role '{}' no longer exists on realm '{}'"
                        .format(self._transport._authrole, realm))

            else:
                ## if authentication is enabled on the transport ..
                ##
                if "auth" in self._transport_config:

                    ## iterate over authentication methods announced by client ..
                    ##
                    for authmethod in details.authmethods or ["anonymous"]:

                        ## .. and if the configuration has an entry for the authmethod
                        ## announced, process ..
                        if authmethod in self._transport_config["auth"]:

                            ## "WAMP-Challenge-Response" authentication
                            ##
                            if authmethod == u"wampcra":
                                cfg = self._transport_config['auth']['wampcra']

                                if cfg['type'] == 'static':
                                    if details.authid in cfg.get('users', {}):
                                        user = cfg['users'][details.authid]

                                        self._pending_auth = PendingAuthWampCra(
                                            details.pending_session,
                                            details.authid, user['role'],
                                            u'static',
                                            user['secret'].encode('utf8'))

                                        ## send challenge to client
                                        ##
                                        extra = {
                                            u'challenge':
                                            self._pending_auth.challenge
                                        }

                                        ## when using salted passwords, provide the client with
                                        ## the salt and then PBKDF2 parameters used
                                        if 'salt' in user:
                                            extra[u'salt'] = user['salt']
                                            extra[u'iterations'] = user.get(
                                                'iterations', 1000)
                                            extra[u'keylen'] = user.get(
                                                'keylen', 32)

                                        return types.Challenge(
                                            u'wampcra', extra)

                                    else:
                                        return types.Deny(
                                            message=
                                            "no user with authid '{}' in user database"
                                            .format(details.authid))

                                elif cfg['type'] == 'dynamic':

                                    ## Get the Crossbar.io service session on the router/realm
                                    ## to issue the WAMP call to the custom authorizer
                                    ##
                                    router = self._router_factory.get(realm)
                                    service_session = router._realm.session

                                    d = service_session.call(
                                        cfg['authenticator'], realm,
                                        details.authid)

                                    def on_authenticate_ok(user):

                                        ## construct a pending WAMP-CRA authentication
                                        ##
                                        self._pending_auth = PendingAuthWampCra(
                                            details.pending_session,
                                            details.authid, user['role'],
                                            u'dynamic',
                                            user['secret'].encode('utf8'))

                                        ## send challenge to client
                                        ##
                                        extra = {
                                            u'challenge':
                                            self._pending_auth.challenge
                                        }

                                        ## when using salted passwords, provide the client with
                                        ## the salt and the PBKDF2 parameters used
                                        ##
                                        if 'salt' in user:
                                            extra[u'salt'] = user['salt']
                                            extra[u'iterations'] = user.get(
                                                'iterations', 1000)
                                            extra[u'keylen'] = user.get(
                                                'keylen', 32)

                                        return types.Challenge(
                                            u'wampcra', extra)

                                    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 = err.value.args[0]

                                        return types.Deny(error, message)

                                    d.addCallbacks(on_authenticate_ok,
                                                   on_authenticate_error)

                                    return d

                                else:

                                    return types.Deny(
                                        message=
                                        "illegal WAMP-CRA config (type '{0}' is unknown)"
                                        .format(cfg['type']))

                            ## "Mozilla Persona" authentication
                            ##
                            elif authmethod == u"mozilla_persona":
                                cfg = self._transport_config['auth'][
                                    'mozilla_persona']

                                audience = cfg.get('audience',
                                                   self._transport._origin)
                                provider = cfg.get(
                                    'provider',
                                    "https://verifier.login.persona.org/verify"
                                )

                                ## authrole mapping
                                ##
                                authrole = cfg.get('role', 'anonymous')

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

                                ## ok, now challenge the client for doing Mozilla Persona auth.
                                ##
                                self._pending_auth = PendingAuthPersona(
                                    provider, audience, authrole)
                                return types.Challenge("mozilla-persona")

                            ## "Anonymous" authentication
                            ##
                            elif authmethod == u"anonymous":
                                cfg = self._transport_config['auth'][
                                    'anonymous']

                                ## authrole mapping
                                ##
                                authrole = cfg.get('role', 'anonymous')

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

                                ## authid generation
                                ##
                                if self._transport._cbtid:
                                    ## if cookie tracking is enabled, set authid to cookie value
                                    ##
                                    authid = self._transport._cbtid
                                else:
                                    ## if no cookie tracking, generate a random value for authid
                                    ##
                                    authid = util.newid(24)

                                self._transport._authid = authid
                                self._transport._authrole = authrole
                                self._transport._authmethod = authmethod

                                return types.Accept(
                                    authid=authid,
                                    authrole=authrole,
                                    authmethod=self._transport._authmethod)

                            ## "Cookie" authentication
                            ##
                            elif authmethod == u"cookie":
                                pass
                                # if self._transport._cbtid:
                                #    cookie = self._transport.factory._cookies[self._transport._cbtid]
                                #    authid = cookie['authid']
                                #    authrole = cookie['authrole']
                                #    authmethod = "cookie.{}".format(cookie['authmethod'])
                                #    return types.Accept(authid = authid, authrole = authrole, authmethod = authmethod)
                                # else:
                                #    return types.Deny()

                            else:
                                log.msg("unknown authmethod '{}'".format(
                                    authmethod))
                                return types.Deny(
                                    message="unknown authentication method {}".
                                    format(authmethod))

                    ## if authentication is configured, by default, deny.
                    ##
                    return types.Deny(
                        message=
                        "authentication using method '{}' denied by configuration"
                        .format(authmethod))

                else:
                    ## if authentication is _not_ configured, by default, allow anyone.
                    ##

                    ## authid generation
                    ##
                    if self._transport._cbtid:
                        ## if cookie tracking is enabled, set authid to cookie value
                        ##
                        authid = self._transport._cbtid
                    else:
                        ## if no cookie tracking, generate a random value for authid
                        ##
                        authid = util.newid(24)

                    return types.Accept(authid=authid,
                                        authrole="anonymous",
                                        authmethod="anonymous")

        except Exception as e:
            traceback.print_exc()
            return types.Deny(message="internal error: {}".format(e))