Example #1
0
    def connect(self, host, port, username=None, password=None, retry=False):
        if retry:
            # Launch a client
            self.pbClientFactory = ReconnectingPBClientFactory()
            self.pbClientFactory.gotPerspective = self._connected
            self.pbClientFactory.disconnected = self._disconnected

            # Start login
            if username is None and password is None:
                self.pbClientFactory.startLogin(
                    Anonymous())
            else:
                self.pbClientFactory.startLogin(
                    UsernamePassword(
                        username,
                        password))

            reactor.connectTCP(host, port, self.pbClientFactory)
        else:
            # Launch a client
            self.pbClientFactory = pb.PBClientFactory()
            reactor.connectTCP(host, port, self.pbClientFactory)

            yield self.pbClientFactory.getRootObject()

            if username is None and password is None:
                yield self.pbClientFactory.login(
                    Anonymous()).addCallback(self._connected)
            else:
                yield self.pbClientFactory.login(
                    UsernamePassword(
                        username,
                        password)).addCallback(self._connected)
Example #2
0
    def getChildWithDefault(self, path, request):
        """
        Inspect the Authorization HTTP header, and return a deferred which,
        when fired after successful authentication, will return an authorized
        C{Avatar}. On authentication failure, an C{UnauthorizedResource} will
        be returned, essentially halting further dispatch on the wrapped
        resource and all children
        """
        authheader = request.getHeader('authorization')
        if not authheader:
            return util.DeferredResource(self._login(Anonymous()))

        factory, respString = self._selectParseHeader(authheader)
        if factory is None:
            return UnauthorizedResource(self._credentialFactories)
        try:
            credentials = factory.decode(respString, request)
        except error.LoginFailed:
            return UnauthorizedResource(self._credentialFactories)
        except:
            log.err(None, "Unexpected failure from credentials factory")
            return ErrorPage(500, None, None)
        else:
            request.postpath.insert(0, request.prepath.pop())
            return util.DeferredResource(self._login(credentials))
Example #3
0
    def requestAvatarId(self, credentials):
        if IAnonymous.providedBy(credentials):
            return defer.succeed(Anonymous())

        uuid = credentials.username
        token = credentials.password

        # lookup key is a hash of the token to prevent timing attacks.
        # TODO cache the tokens already!

        db = self._tokens_db()
        token = db.get(sha512(token).hexdigest())
        if token is None:
            return defer.fail(error.UnauthorizedLogin())

        # TODO -- use cryptography constant time builtin comparison.
        # we compare uuid hashes to avoid possible timing attacks that
        # might exploit python's builtin comparison operator behaviour,
        # which fails immediatelly when non-matching bytes are found.
        couch_uuid_hash = sha512(token[self.TOKENS_USER_ID_KEY]).digest()
        req_uuid_hash = sha512(uuid).digest()
        if token[self.TOKENS_TYPE_KEY] != self.TOKENS_TYPE_DEF \
                or couch_uuid_hash != req_uuid_hash:
            return defer.fail(error.UnauthorizedLogin())

        return defer.succeed(uuid)
Example #4
0
    def _authorizedResource(self, request):
        # check whether the path of the request exists in the app
        match = self._matchPath(request)
        if not match:
            return UnauthorizedResource()

        # get authorization header or fail
        header = request.getHeader(b'authorization')
        if not header:
            return util.DeferredResource(self._login(Anonymous()))

        # parse the authorization header
        auth_data = self._parseHeader(header)
        if not auth_data:
            return UnauthorizedResource()

        # decode the credentials from the parsed header
        try:
            credentials = self._credentialFactory.decode(auth_data, request)
        except error.LoginFailed:
            return UnauthorizedResource()
        except:
            # If you port this to the newer log facility, be aware that
            # the tests rely on the error to be logged.
            log.err(None, "Unexpected failure from credentials factory")
            return ErrorPage(500, None, None)

        # make sure the uuid given in path corresponds to the one given in
        # the credentials
        request_uuid = match.get('uuid')
        if request_uuid and request_uuid != credentials.username:
            return ErrorPage(500, None, None)

        # if all checks pass, try to login with credentials
        return util.DeferredResource(self._login(credentials))
Example #5
0
    def getChild(self, path, request):
        s = request.getSession()
        if s is None:
            return request.setupSession()
        if path == INIT_PERSPECTIVE:

            def loginSuccess(result):
                interface, avatarAspect, logout = result
                s.setResourceForPortal(avatarAspect, self.portal, logout)

            def triggerLogin(username, password, submit=None):
                return self.portal.login(
                    UsernamePassword(username, password), None,
                    IResource).addCallback(loginSuccess).addErrback(
                        self._ebFilter)

            return form.FormProcessor(newLoginSignature.method(triggerLogin),
                                      callback=self.callback,
                                      errback=self.errback)
        elif path == DESTROY_PERSPECTIVE:
            s.portalLogout(self.portal)
            return Redirect(".")
        else:
            r = s.resourceForPortal(self.portal)
            if r:
                ## Delegate our getChild to the resource our portal says is the right one.
                return getResource(r[0], path, request)
            else:
                return DeferredResource(
                    self.portal.login(Anonymous(), None, IResource).
                    addCallback(
                        lambda (interface, avatarAspect, logout): getResource(
                            s.setResourceForPortal(avatarAspect, self.portal,
                                                   logout), path, request)))
Example #6
0
    def __init__(self,
                 url,
                 version=jsonrpc.VERSION_1,
                 connectTimeout=None,
                 credentials=None,
                 contextFactory=None,
                 pool=None):
        """
        @type url: str
        @param url: URL of the RPC server. Supports HTTP and HTTPS for now,
        more might come in the future.

        @type version: int
        @param version: Which JSON-RPC version to use? The default is 1.0.

        @type connectTimeout: float
        @param connectTimeout: Connection timeout. Note that we don't connect
            when creating this object, but in callRemote, so the timeout
            will apply to callRemote.

        @type credentials: twisted.cred.credentials.ICredentials
        @param credentials: Credentials for basic HTTP authentication.
            Supported are Anonymous and UsernamePassword classes.
            If None then t.c.c.Anonymous object is used as default.

        @type contextFactory: twisted.internet.ssl.ClientContextFactory
        @param contextFactory: A context factory for SSL clients.
            If None then Agent's default is used.

        @type pool: twisted.web.client.HTTPConnectionPool
        @param pool: Connection pool used to manage HTTP connections.
            If None then Agent's default is used.
        """

        self.url = url
        self.version = version

        if not credentials:
            credentials = Anonymous()

        if not isinstance(credentials, (Anonymous, UsernamePassword)):
            raise NotImplementedError("'%s' credentials are not supported" %
                                      type(credentials))

        kwargs = {}

        if connectTimeout:
            kwargs['connectTimeout'] = connectTimeout

        if contextFactory:
            kwargs['contextFactory'] = contextFactory

        if pool:
            kwargs['pool'] = pool

        self.agent = Agent(reactor, **kwargs)
        self.credentials = credentials
        self.auth_headers = None
Example #7
0
    def connect(self, host, port, username=None, password=None):
        # Launch a client
        self.pbClientFactory = pb.PBClientFactory()
        reactor.connectTCP(host, port, self.pbClientFactory)

        if username is None and password is None:
            return self.pbClientFactory.login(Anonymous()).addCallback(
                self._connected)
        else:
            return self.pbClientFactory.login(
                UsernamePassword(username,
                                 password)).addCallback(self._connected)
Example #8
0
    def test_anonymousError(self):
        addr = 'http://localhost:%s' % self.portNumber
        proxy = Proxy(addr, credentials=Anonymous())
        d = proxy.callRemote('echo', '')
        e = self.assertFailure(d, jsonrpc.JSONRPCError)

        def finished(result):
            self.assertEquals(result.strerror, 'Unauthorized')
            self.assertEquals(result.errno, jsonrpc.INVALID_REQUEST)

        e.addCallback(finished)
        return d
Example #9
0
    def test_anonymousLogin(self):
        data = 'some random string'

        addr = 'http://localhost:%s' % self.portNumber
        proxy = Proxy(addr, jsonrpc.VERSION_1, credentials=Anonymous())
        d = proxy.callRemote('echo', data)

        def finished(result):
            self.assertEquals(result, data)

        d.addCallback(finished)
        return d
Example #10
0
    def requestAvatarId(self, credentials):
        if IAnonymous.providedBy(credentials):
            return defer.succeed(Anonymous())

        service = credentials.username
        token = credentials.password

        # TODO: Use constant time comparison
        if self._trusted_services_tokens[service] != token:
            return defer.fail(error.UnauthorizedLogin())

        return defer.succeed(service)
Example #11
0
    def test_sessionCleanup(self):
        """
        Expired sessions are cleaned up every C{sessionCleanFrequency} seconds.
        """
        clock = Clock()
        store = Store()
        portal = Portal(_TrivialRealm())
        portal.registerChecker(AllowAnonymousAccess(), IAnonymous)
        request = FakeRequest(headers={'host': 'example.com'})
        resource = PersistentSessionWrapper(
            store, portal, domains=['example.org', 'example.com'], clock=clock)
        session = GuardSession(resource, b'uid')

        # Create two sessions
        resource.createSessionForKey(b'key1', b'username@domain')
        resource.createSessionForKey(b'key2', b'username@domain')
        self.assertEqual(store.query(PersistentSession).count(), 2)

        # Session shouldn't be cleaned yet
        resource.login(request, session, Anonymous(), ())
        self.assertEqual(store.query(PersistentSession).count(), 2)

        # First session is expired and it's time for a clean
        ps = store.findUnique(PersistentSession,
                              PersistentSession.sessionKey == b'key1')
        ps.lastUsed -= timedelta(seconds=PERSISTENT_SESSION_LIFETIME + 1)
        clock.advance(SESSION_CLEAN_FREQUENCY + 1)
        resource.login(request, session, Anonymous(), ())
        self.assertEqual(
            list(store.query(PersistentSession).getColumn('sessionKey')),
            [b'key2'])

        # Now we expire the second session
        ps2 = store.findUnique(PersistentSession,
                               PersistentSession.sessionKey == b'key2')
        ps2.lastUsed -= timedelta(seconds=PERSISTENT_SESSION_LIFETIME + 1)
        clock.advance(SESSION_CLEAN_FREQUENCY + 1)
        resource.login(request, session, Anonymous(), ())
        self.assertEqual(store.query(PersistentSession).count(), 0)
Example #12
0
    def remote_loginAnonymous(self, mind):
        """
        Attempt an anonymous login.

        @param mind: An object to use as the mind parameter to the portal login
            call (possibly None).

        @rtype: L{Deferred}
        @return: A Deferred which will be called back with an avatar when login
            succeeds or which will be errbacked if login fails somehow.
        """
        d = self.portal.login(Anonymous(), mind, IPerspective)
        d.addCallback(self._cbLogin)
        return d
Example #13
0
 def xmlrpc_authenticate(self, username, password):
     """server authentication method"""
     print "MaayRPCServer xmlrpc_authenticate", username
     # anonymous login
     if (username, password) == ('', ''):
         creds = Anonymous()
         onSuccess = lambda d,u,p: (ANONYMOUS_AVATARID, '')
     else:
         creds = UsernamePassword(username, password)
         onSuccess = self._attachUser
     d = self.portal.login(creds, None, IQuerier)
     d.addCallback(onSuccess, username, password) # self._attachUser, username, password)
     d.addErrback(lambda failure: ('', str(failure)))
     return d
Example #14
0
 def _get_or_create_session(self, provider, full_id, password=""):
     if full_id in self._sessions:
         return self._sessions[full_id]
     if full_id == ANONYMOUS:
         credentials = Anonymous()
         provider_id = provider.domain
     else:
         username, provider_id = config.get_username_and_provider(full_id)
         credentials = UsernamePassword(username, password)
     api = self._get_api(provider)
     provider_pem = config.get_ca_cert_path(_preffix, provider_id)
     session = Session(credentials, api, provider_pem)
     self._sessions[full_id] = session
     return session
Example #15
0
    def _authorizedResource(self, request):
        # check whether the path of the request exists in the app
        match = self._matchPath(request)
        if not match:
            return UnauthorizedResource()

        # get authorization header or fail
        header = request.getHeader(b'authorization')
        if not header:
            return util.DeferredResource(self._login(Anonymous()))

        # parse the authorization header
        auth_data = self._parseHeader(header)
        if not auth_data:
            return UnauthorizedResource()

        # decode the credentials from the parsed header
        try:
            credentials = self._credentialFactory.decode(auth_data, request)
        except error.LoginFailed:
            return UnauthorizedResource()
        except Exception:
            # If you port this to the newer log facility, be aware that
            # the tests rely on the error to be logged.
            log.err(None, "Unexpected failure from credentials factory")
            return ErrorPage(500, None, None)

        # make sure the uuid given in path corresponds to the one given in
        # the credentials
        request_uuid = match.get('uuid')
        if request_uuid and request_uuid != credentials.username:
            return ErrorPage(500, None, None)

        # eventually return a cached resouce
        sessionData = _sessionData(request)
        if sessionData.username == credentials.username \
                and sessionData.password == credentials.password:
            return self._portal.realm.auth_resource

        # if all checks pass, try to login with credentials and cache
        # credentials in case of success
        def _cacheSessionData(res):
            sessionData.username = credentials.username
            sessionData.password = credentials.password
            return res

        d = self._login(credentials)
        d.addCallback(_cacheSessionData)
        return util.DeferredResource(d)
Example #16
0
    def _authorizedResource(self, request):
        """
        Get the L{IResource} which the given request is authorized to receive.
        If the proper authorization headers are present, the resource will be
        requested from the portal.  If not, an anonymous login attempt will be
        made.
        """
        cert = request.channel.transport.getPeerCertificate()

        # Anonymous access if no certificate
        if not cert:
            return webutil.DeferredResource(self._login(Anonymous()))

        # TODO hard-coded to Kontalk usage
        return webutil.DeferredResource(self._login(self._credential(cert)))
Example #17
0
    def _get_config_for_all_services(self, session):
        if session is None:
            provider_cert = self._get_ca_cert_path()
            session = Session(Anonymous(), self.api_uri, provider_cert)

        services_dict = self._load_provider_configs()
        configs_path = self._get_configs_path()
        with open(configs_path) as jsonf:
            services_dict = Record(**json.load(jsonf)).services
        pending = []
        base = self._disco.get_base_uri()
        for service in self._provider_config.services:
            if service in self.SERVICES_MAP.keys():
                for subservice in self.SERVICES_MAP[service]:
                    uri = base + str(services_dict[subservice])
                    path = self._get_service_config_path(subservice)
                    d = session.fetch_provider_configs(uri, path, method='GET')
                    pending.append(d)
        return defer.gatherResults(pending)
Example #18
0
 def _reconnect(self):
     try:
         if self._client:
             self._client.disconnect()
         self._client = PBClientFactory()
         if self._listener:
             self._listener.disconnect()
         self._listener = reactor.connectTCP(self.forwardserver,
                                             self.forwardport, self._client)
         self._remote = self._client.login(Anonymous())
         self._remote.addCallback(self._login)
         self._remote.addErrback(self._loginFailed)
     except Exception, e:
         logger.error(
             "[output:%s] failed to connect to remote collector: %s" %
             (self.name, str(e)))
         logger.error("[output:%s] will retry to connect in %i seconds" %
                      (self.name, self.retryinterval))
         self._backoff = reactor.callLater(self.retryinterval,
                                           self._reconnect)
Example #19
0
def main():
    """
    Connect to a PB server running on port 8800 on localhost and log in to
    it, both anonymously and using a username/password it will recognize.
    """
    startLogging(stdout)
    factory = PBClientFactory()
    reactor.connectTCP("localhost", 8800, factory)

    anonymousLogin = factory.login(Anonymous())
    anonymousLogin.addCallback(connected)
    anonymousLogin.addErrback(error, "Anonymous login failed")

    usernameLogin = factory.login(UsernamePassword("user1", "pass1"))
    usernameLogin.addCallback(connected)
    usernameLogin.addErrback(error, "Username/password login failed")

    bothDeferreds = gatherResults([anonymousLogin, usernameLogin])
    bothDeferreds.addCallback(finished)

    reactor.run()
Example #20
0
    def __init__(self,
                 url,
                 version=jsonrpc.VERSION_1,
                 connectTimeout=None,
                 credentials=Anonymous(),
                 contextFactory=WebClientContextFactory()):
        """
        @type url: str
        @param url: URL of the RPC server. Supports HTTP and HTTPS for now,
        more might come in the future.

        @type version: int
        @param version: Which JSON-RPC version to use? The default is 1.0.

        @type connectTimeout: float
        @param connectTimeout: Connection timeout. Note that we don't connect
            when creating this object, but in callRemote, so the timeout
            will apply to callRemote.

        @type credentials: twisted.cred.credentials.ICredentials
        @param credentials: Credentials for basic HTTP authentication.
            Supported are Anonymous and UsernamePassword classes.

        @type contextFactory: twisted.internet.ssl.ClientContextFactory
        @param contextFactory: A context factory for SSL clients.
        """

        self.url = url
        self.version = version

        if not isinstance(credentials, (Anonymous, UsernamePassword)):
            raise NotImplementedError("'%s' credentials are not supported" %
                                      type(credentials))

        self.agent = Agent(reactor,
                           connectTimeout=connectTimeout,
                           contextFactory=contextFactory)
        self.credentials = credentials
        self.auth_headers = None
Example #21
0
    def _authorizedResource(self, request):
        """
        Get the L{IResource} which the given request is authorized to receive.
        If the proper authorization headers are present, the resource will be
        requested from the portal.  If not, an anonymous login attempt will be
        made.
        """
        authheader = request.getHeader(b'authorization')
        if not authheader:
            return util.DeferredResource(self._login(Anonymous()))

        factory, respString = self._selectParseHeader(authheader)
        if factory is None:
            return UnauthorizedResource(self._credentialFactories)
        try:
            credentials = factory.decode(respString, request)
        except error.LoginFailed:
            return UnauthorizedResource(self._credentialFactories)
        except:
            self._log.failure("Unexpected failure from credentials factory")
            return ErrorPage(500, None, None)
        else:
            return util.DeferredResource(self._login(credentials))
Example #22
0
    def _authorizedResource(self, request):
        """
        Get the L{IResource} which the given request is authorized to receive.
        If the proper authorization 
        """
        sess = request.getSession()
        if sess.uid not in self.sessions:
            # New Session
            self.sessions.add(sess.uid)
            sess.notifyOnExpire(lambda: self._expired(sess))

        # Session is authenticated already
        if sess.is_authed():
            return util.DeferredResource(
                self._login(SessionCookie(request), sess))

        # Perform an Anonymous login
        if not self.check_credentials(request):
            return util.DeferredResource(self._login(Anonymous(), sess))

        # Try to authenticate the session
        return util.DeferredResource(
            self._login(self.get_credentials(request), sess))
Example #23
0
 def render_POST(self, request):
     params = get_unicode_params(request)
     action = params.get(u"action", [u"login"])[0]
     
     if action == u"prepare":
         # prepare client token
         token = params.get(u"token", [None])[0]
         secret = params.get(u"secret", [None])[0]
         
         if (token is None) and (secret is None):
             # anonymous website
             credentials = Anonymous()
         elif (token is None) or (secret is None):
             # one value is missing, invalid request
             defer.returnValue(u'{"status": "error", "reason": "token OR secret missing"}')
         else:
             # token / secret provided
             credentials = UnicodeUsernamePassword(token, secret)
         
         try:
             _, perm, logout = yield self._token_portal.login(credentials, None, IWebAuthPermission)
         except (Unauthorized, LoginFailed):
             defer.returnValue(u'{"status": "error", "reason": "token/secret invalid"}')
         else:
             # this is not an interactive season, so call logout immediately
             logout()
         
         ctoken = self._new_ctoken()
         self._tokens[ctoken] = (self._TOKEN_STATE_LOGIN, perm, None)
         defer.returnValue(u'{"status": "success", "client_token": "' + ctoken + '"}')
     elif action == u"login":
         # login credentials
         params = get_unicode_params(request)
         ctoken = params.get("ctoken", [None])[0]
         
         if ctoken not in self._tokens:
             # invalid client token
             html = (yield self._login_resource.render_invalid_login(request)) or u"Error: Invalid ctoken"
             defer.returnValue(html)
         
         credentials = self._login_resource.handle_login_response(params)
         
         # attempt login
         try:
             _, userdata, logout = yield self._user_portal.login(credentials, None, IUserData)
         except (Unauthorized, LoginFailed):
             # invalid login
             response = (yield self._login_resource.render_login_failed(request)) or u"Login failed"
             defer.returnValue(response)
         else:
             # login successfull
             # first off, call logout as twisted cred wants
             logout()
             # secondly, set the client login cookie
             session = request.getSession()
             cookie = ILoginCookie(session)
             cookie.userdata = userdata
             # thirdly, prepare the userdata
             _, perm, _2 = self._tokens[ctoken]
             self._tokens[ctoken] = (self._TOKEN_STATE_CB, perm, userdata)
             # finally, redirect to callback
             defer.returnValue(
                 redirectTo(
                     u"{}?action=callback&ctoken={}".format(
                         perm.callback_url,
                         ctoken,
                     ).encode(_URL_ENCODING),
                     request,
                 )
             )
     else:
         # unknown action
         request.setResponseCode(404)
         defer.returnValue(u"Error: Invalid action specified.")
Example #24
0
    def checkLogin(self,
                   ctx,
                   session,
                   segments,
                   sessionURL=None,
                   httpAuthCredentials=None):
        """
        Associate the given request with the given session and:

            - log the user in to our portal, if they are accessing a login URL

            - log the user out from our portal (calling their logout callback),
              if they are logged in and accessing a logout URL

            - Move the request parameters saved on the session, if there are
              any, onto the request if a session just started or a login
              just succeeded.

        @return:

            - if the user is already logged in: a 2-tuple of requestObject,
              C{segments} (i.e. the segments parameter)

            - if the user is not logged in and not logging in, call login() to
              initialize an anonymous session, and return a 2-tuple of
              (rootResource, segments-parameter) from that anonymous session.
              This counts as logging in for the purpose of future calls to
              checkLogin.

            - if the user is accessing a login URL: a 2-tuple of the logged in
              resource object root and the remainder of the segments (i.e. the
              URL minus __login__) to be passed to that resource.

        """
        request = inevow.IRequest(ctx)
        session.touch()
        request.session = session
        root = url.URL.fromContext(request)
        if sessionURL is not None:
            root = root.child(sessionURL)
        request.rememberRootURL(str(root))

        spoof = False
        if getattr(session, 'sessionJustStarted', False):
            del session.sessionJustStarted
            spoof = True
        if getattr(session, 'justLoggedIn', False):
            del session.justLoggedIn
            spoof = True
        if spoof and hasattr(session, 'args'):
            request.args = session.args
            request.fields = session.fields
            request.content = StringIO.StringIO()
            request.content.close()
            request.method = session.method
            request.received_headers = session.received_headers

            del session.args, session.fields, session.method, session.received_headers

        if segments and segments[0] in (LOGIN_AVATAR, LOGOUT_AVATAR):
            authCommand = segments[0]
        else:
            authCommand = None

        if httpAuthCredentials:
            # This is the FIRST TIME we have hit an HTTP auth session with our
            # credentials.  We are going to perform login.
            assert not authCommand, (
                "HTTP auth support isn't that robust.  "
                "Come up with something to do that makes sense here.")
            return self.login(request, session, httpAuthCredentials,
                              segments).addErrback(self.authRequiredError,
                                                   session)

        if authCommand == LOGIN_AVATAR:
            subSegments = segments[1:]

            def unmangleURL((res, segs)):
                # Tell the session that we just logged in so that it will
                # remember form values for us.
                session.justLoggedIn = True
                # Then, generate a redirect back to where we're supposed to be
                # by looking at the root of the site and calculating the path
                # down from there using the segments we were passed.
                u = url.URL.fromString(request.getRootURL())
                for seg in subSegments:
                    u = u.child(seg)
                return u, ()

            return self.login(request, session, self.getCredentials(request),
                              subSegments).addCallback(unmangleURL).addErrback(
                                  self.incorrectLoginError, ctx, subSegments,
                                  "Incorrect login.")
        elif authCommand == LOGOUT_AVATAR:
            self.explicitLogout(session)
            return urlToChild(ctx, *segments[1:]), ()
        else:
            r = session.resourceForPortal(self.portal)
            if r:
                ## Delegate our getChild to the resource our portal says is the right one.
                return r[0], segments
            else:
                # XXX I don't think that the errback here will work at all,
                # because the redirect loop would be infinite.  Perhaps this
                # should be closer to the HTTP auth path?
                return self.login(request, session, Anonymous(),
                                  segments).addErrback(
                                      self.incorrectLoginError, ctx, segments,
                                      'Anonymous access not allowed.')