def _set_response(self, environ, start_response, oid_request,
                      identity_uri):
        '''Add Attribute exchange parameters to the response if OpenID Relying
        Party requested them
        
        @type oid_request: openid.server.server.CheckIDRequest
        @param oid_request: OpenID Check ID request
        @rtype: basestring
        @return: WSGI response
        '''
        # Process any request for additional attributes contained in the query
        # from the Relying Party
        oid_response = oid_request.answer(True, identity=identity_uri)

        try:
            self._add_ax_response(oid_request, oid_response)

        except (OpenIDProviderMissingRequiredAXAttrs,
                OpenIDProviderMissingAXResponseHandler):
            log.error('The requesting Relying Party requires additional '
                      'attributes which this site isn\'t configured to '
                      'provide.')
            raise HTTPUnauthorized()

        except OpenIDProviderReloginRequired, e:
            log.error('An error occurred setting return attribute parameters '
                      'required by the Relying Party requesting your ID.')
            raise HTTPUnauthorized()
Ejemplo n.º 2
0
 def build_authentication(self):
     head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
     if self._rc_auth_http_code and self._rc_auth_http_code == '403':
         # return 403 if alternative http return code is specified in
         # RhodeCode config
         return HTTPForbidden(headers=head)
     return HTTPUnauthorized(headers=head)
Ejemplo n.º 3
0
Archivo: basic.py Proyecto: bjornua/dna
    def identify(self, environ):
        path_info = environ['PATH_INFO']
        query = parse_dict_querystring(environ)

        # This will handle the logout request.
        if path_info == self._logout_url:
            # set in environ for self.challenge() to find later
            environ['repoze.who.application'] = HTTPUnauthorized()
            return None
        elif path_info == self._login_url:
            form = parse_formvars(environ)
            form.update(query)
            try:
                credentials = {
                    'login': form['login'],
                    'password': form['password']
                }
            except KeyError:
                credentials = None

            def auth_resp(environ, start_response):
                import json
                resp = {"success": True}

                resp_str = json.dumps(resp)

                content_length = CONTENT_LENGTH.tuples(str(len(resp_str)))
                content_type = CONTENT_TYPE.tuples('application/json')
                headers = content_length + content_type
                start_response('200 OK', headers)
                return [resp_str]

            environ['repoze.who.application'] = auth_resp
            return credentials
Ejemplo n.º 4
0
    def identify(self, environ):
        
        if environ['PATH_INFO'] == self.login_handler_path:
            ## We are on the URL where repoze.who processes authentication. ##
            form = parse_formvars(environ)
            try:
                credentials = {
                    'login': form['login'],
                    'password': form['password']
                    }
            except KeyError:
                credentials = None
            
            # destination is the post-login page
            destination = self._get_full_path(self.post_login_url, environ)
            # all variables from query string are kept in query string
            destination = self._replace_qs(destination, environ.get('QUERY_STRING'))

            environ['repoze.who.application'] = HTTPFound(destination)
            return credentials

        elif environ['PATH_INFO'] == self.logout_handler_path:
            ##    We are on the URL where repoze.who logs the user out.    ##
            # let's throw an exception to get challenged
            environ['repoze.who.application'] = HTTPUnauthorized()
            return None
Ejemplo n.º 5
0
 def secret_for_others(self, environ, start_response):
     r"""This can not be accessed from oauth"""
     if not not_oauth().is_met(environ):
         start_response('401 ', [('Content-Type', 'text/plain')])
         return HTTPUnauthorized()
     start_response('200 OK', [('Content-Type', 'text/plain')])
     return ['This is for all except oauth']
Ejemplo n.º 6
0
 def secret_for_app1(self, environ, start_response):
     r"""This can be accessed by app1 consumer only"""
     if not is_consumer('app1').is_met(environ):
         start_response('401 ', [('Content-Type', 'text/plain')])
         return HTTPUnauthorized()
     start_response('200 OK', [('Content-Type', 'text/plain')])
     return ['This is a secret for app1 only']
Ejemplo n.º 7
0
    def test_call_200_identity_reset(self):
        environ = self._makeEnviron()
        headers = [('a', '1')]
        new_identity = {'user_id':'foo', 'password':'******'}
        app = DummyIdentityResetApp('200 OK', headers, new_identity)
        from paste.httpexceptions import HTTPUnauthorized
        challenge_app = HTTPUnauthorized()
        challenge = DummyChallenger(challenge_app)
        challengers = [ ('challenge', challenge) ]
        credentials = {'login':'******', 'password':'******'}
        identifier = DummyIdentifier(credentials)
        identifiers = [ ('identifier', identifier) ]
        authenticator = DummyAuthenticator()
        authenticators = [ ('authenticator', authenticator) ]
        mw = self._makeOne(app=app, challengers=challengers,
                           identifiers=identifiers,
                           authenticators=authenticators)
        start_response = DummyStartResponse()
        result = mw(environ, start_response)
        self.assertEqual(environ.get('challenged'), None)
        self.assertEqual(identifier.forgotten, False)
        new_credentials = identifier.credentials.copy()
        new_credentials['login'] = '******'
        new_credentials['password'] = '******'
        # @@ unfuck
##         self.assertEqual(identifier.remembered, new_credentials)
        self.assertEqual(environ['REMOTE_USER'], 'chris')
Ejemplo n.º 8
0
    def identify(self, environ):
        path_info = environ['PATH_INFO']
        query = parse_dict_querystring(environ)

        if path_info == self.logout_handler_path:
            # we've been asked to perform a logout
            form = parse_formvars(environ)
            form.update(query)
            referer = environ.get('HTTP_REFERER', '/')
            environ['repoze.who.application'] = HTTPUnauthorized()

            # invalidate the session
            identity = environ.get('repoze.who.identity')
            if identity:
                self.forget(environ, identity)

            return None

        elif path_info == self.login_handler_path:
            # we've been asked to perform a login
            form = parse_formvars(environ)
            form.update(query)

            credentials = self._getCredentials(form)

            referer = environ.get('HTTP_REFERER', '/')
            environ['repoze.who.application'] = HTTPFound(referer)
            if 'login' not in credentials or 'password' not in credentials:
                return None
            return credentials
Ejemplo n.º 9
0
 def challenge(self, environ, status, app_headers, forget_headers):
     """Return a 401 page unconditionally."""
     headers = app_headers + forget_headers
     # The HTTP status code and reason may not be the default ones:
     status_parts = _HTTP_STATUS_PATTERN.search(status)
     if status_parts:
         reason = status_parts.group('reason')
         code = int(status_parts.group('code'))
     else:
         reason = 'HTTP Unauthorized'
         code = 401
     # Building the response:
     response = HTTPUnauthorized(headers=headers)
     response.title = reason
     response.code = code
     return response
Ejemplo n.º 10
0
    def identify(self, environ):
        path_info = environ['PATH_INFO']
        query = parse_dict_querystring(environ)

        if path_info == self.logout_handler_path:
            # we've been asked to perform a logout
            form = parse_formvars(environ)
            form.update(query)
            referer = environ.get('HTTP_REFERER', '/')
            environ['repoze.who.application'] = HTTPUnauthorized()
            return None

        elif path_info == self.login_handler_path:
            # we've been asked to perform a login
            form = parse_formvars(environ)
            form.update(query)
            try:
                max_age = form.get('max_age', None)
                credentials = {
                    'login': form['login'],
                    'password': form['password'],
                    'realm': form['realm'],
                }
            except KeyError:
                credentials = None

            if credentials is not None:
                max_age = form.get('max_age', None)
                if max_age is not None:
                    credentials['max_age'] = max_age

            referer = environ.get('HTTP_REFERER', '/')
            environ['repoze.who.application'] = HTTPFound(referer)
            return credentials
Ejemplo n.º 11
0
 def challenge(self, environ, status, app_headers, forget_headers):
     """Return a 401 page unconditionally."""
     headers = app_headers + forget_headers
     remove_header(headers, 'content-length')
     # The HTTP status code and reason may not be the default ones:
     status_parts = _HTTP_STATUS_PATTERN.search(status)
     if status_parts:
         reason = status_parts.group('reason')
         code = int(status_parts.group('code'))
     else:
         reason = 'HTTP Unauthorized'
         code = 401
     # Building the response:
     response = HTTPUnauthorized(headers=headers)
     response.title = reason
     response.code = code
     return response
Ejemplo n.º 12
0
 def about(self):
     if request.environ.get('repoze.who.identity') == None:
         raise HTTPUnauthorized()
     user = request.environ['repoze.who.identity']['repoze.who.userid']
     flash('Your Distinguished Name (DN) is "%s"' % user)
     # Passing the metadata
     metadata = request.environ['repoze.who.identity']
     return dict(metadata=metadata.items())
Ejemplo n.º 13
0
 def challenge(self, environ, status, app_headers, forget_headers):
     r"""If the request failed due to invalid or insufficient parameters or
     permissions return a WWW-Authenticate header with the realm.
     """
     # Add the WWW-Authenticate header
     headers = WWW_AUTHENTICATE.tuples('OAuth realm="%s"' % self.realm)
     if headers[0] not in forget_headers:
         headers += forget_headers
     return HTTPUnauthorized(headers=headers)
Ejemplo n.º 14
0
 def build_authentication(self):
     head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
     if self._rc_auth_http_code and not self.initial_call:
         # return alternative HTTP code if alternative http return code
         # is specified in RhodeCode config, but ONLY if it's not the
         # FIRST call
         custom_response_klass = self._get_response_from_code(
             self._rc_auth_http_code)
         return custom_response_klass(headers=head)
     return HTTPUnauthorized(headers=head)
    def _authenticate(self, environ, username, password):
        self.session = environ.get(self.session_mware_environ_keyname, {})
        if (OpenIDProviderMiddleware.USERNAME_SESSION_KEYNAME in self.session):
            # user is already logged in
            return

        identity_uri = None

        if None in (username, password):
            raise HTTPUnauthorized()

        # Invoke custom authentication interface plugin
        try:
            self._authN.logon(environ, identity_uri, username, password)

        except AuthNInterfaceError, e:
            log.error("Authentication error: %s", traceback.format_exc())

            raise HTTPUnauthorized()
Ejemplo n.º 16
0
 def add_metadata(self, environ, identity):
     """
     Call the parent MD provider.
     
     :raises HTTPUnauthorized: If the user account no longer exists.
     
     """
     super(SQLAlchemyStrictUserMDPlugin,
           self).add_metadata(environ, identity)
     if identity['user'] is None:
         # The user has been deleted from the database
         raise HTTPUnauthorized()
Ejemplo n.º 17
0
 def build_authentication(self, stale = ''):
     """ builds the authentication error """
     nonce  = md5.md5("%s:%s" % (time.time(),random.random())).hexdigest()
     opaque = md5.md5("%s:%s" % (time.time(),random.random())).hexdigest()
     self.nonce[nonce] = None
     parts = { 'realm': self.realm, 'qop': 'auth',
               'nonce': nonce, 'opaque': opaque }
     if stale:
         parts['stale'] = 'true'
     head = ", ".join(['%s="%s"' % (k,v) for (k,v) in parts.items()])
     head = [("WWW-Authenticate", 'Digest %s' % head)]
     return HTTPUnauthorized(headers=head)
Ejemplo n.º 18
0
 def test_call_401_no_identifiers(self):
     environ = self._makeEnviron()
     headers = [('a', '1')]
     app = DummyWorkingApp('401 Unauthorized', headers)
     from paste.httpexceptions import HTTPUnauthorized
     challenge_app = HTTPUnauthorized()
     challenge = DummyChallenger(challenge_app)
     challengers = [ ('challenge', challenge) ]
     mw = self._makeOne(app=app, challengers=challengers)
     start_response = DummyStartResponse()
     result = mw(environ, start_response)
     self.assertEqual(environ['challenged'], challenge_app)
     self.failUnless(result[0].startswith('401 Unauthorized\r\n'))
    def _resolve_and_validate_identity_uri(self, environ, oid_request,
                                           username):
        '''Get OpenID identity URI and check against credentials provided
        '''
        if oid_request.idSelect():
            # ID select mode enables the user to request specifying
            # their OpenID Provider without giving a personal user URL
            try:
                user_identifiers = self._authN.username2UserIdentifiers(
                    environ, username)
            except AuthNInterfaceInvalidCredentials:
                log.error("No username %r matching an OpenID URL: %s",
                          username, traceback.format_exc())
                raise

            if not isinstance(user_identifiers, (list, tuple)):
                raise TypeError("Unexpected type %r returned from %r for "
                                "user identifiers; expecting list or tuple" %
                                (type(user_identifiers), type(self._authN)))

            # FIXME: Assume the *first* user identifier entry is the
            # one to use.  The user could have multiple identifiers
            # but in practice it's more manageable to have a single one
            identity_uri = self.createIdentityURI(self.identityUriTmpl,
                                                  user_identifiers[0])
        else:
            # Get the unique user identifier from the user's OpenID URL
            identity_uri = oid_request.identity

            # Check the username used to login with matches the identity URI
            # given.  This check is essential otherwise a user could impersonate
            # someone else with an account with this provider
            try:
                user_identifiers = self._authN.username2UserIdentifiers(
                    environ, username)
            except AuthNInterfaceInvalidCredentials:
                log.error("No username %r matching an OpenID URL: %s",
                          username, traceback.format_exc())
                raise

            expected_identity_uri = self.createIdentityURI(
                self.identityUriTmpl, user_identifiers[0])
            if identity_uri != expected_identity_uri:
                log.error("OpenID given %r, doesn't match the expected "
                          "OpenID %r for this account name %r" %
                          (identity_uri, expected_identity_uri, username))

                raise HTTPUnauthorized()

        return identity_uri
Ejemplo n.º 20
0
Archivo: basic.py Proyecto: bjornua/dna
    def challenge(self, environ, status, app_headers, forget_headers):
        cookies = [(h, v) for (h, v) in app_headers
                   if h.lower() == 'set-cookie']
        if not forget_headers:
            return HTTPUnauthorized()

        def auth_form(environ, start_response):
            towrite = "Challenging this"
            content_length = CONTENT_LENGTH.tuples(str(len(towrite)))
            content_type = CONTENT_TYPE.tuples('text/html')
            headers = content_length + content_type + forget_headers
            start_response('200 OK', headers)
            return [towrite]

        return auth_form
Ejemplo n.º 21
0
    def _complete_login(self, environ, start_response):
        """Complete the OpenID authentication process.

        Here we handle the result of the OpenID process.  If the process
        succeeded, we record the username in the session and redirect the user
        to the page they were trying to view that triggered the login attempt.
        In the various failures cases we return a 401 Unauthorized response
        with a brief explanation of what went wrong.
        """
        query = dict(parse_querystring(environ))
        # Passing query['openid.return_to'] here is massive cheating, but
        # given we control the endpoint who cares.
        response = self._make_consumer(environ).complete(
            query, query['openid.return_to'])
        if response.status == SUCCESS:
            self.log.error('open id response: SUCCESS')
            sreg_info = SRegResponse.fromSuccessResponse(response)
            if not sreg_info:
                self.log.error('sreg_info is None.')
                exc = HTTPUnauthorized()
                exc.explanation = (
                  "You don't have a Launchpad account. Check that you're "
                  "logged in as the right user, or log into Launchpad and try "
                  "again.")
                raise exc
            environ[self.session_var]['user'] = sreg_info['nickname']
            raise HTTPMovedPermanently(query['back_to'])
        elif response.status == FAILURE:
            self.log.error('open id response: FAILURE: %s', response.message)
            exc = HTTPUnauthorized()
            exc.explanation = response.message
            raise exc
        elif response.status == CANCEL:
            self.log.error('open id response: CANCEL')
            exc = HTTPUnauthorized()
            exc.explanation = "Authentication cancelled."
            raise exc
        else:
            self.log.error('open id response: UNKNOWN')
            exc = HTTPUnauthorized()
            exc.explanation = "Unknown OpenID response."
            raise exc
Ejemplo n.º 22
0
    def test_call_401_challenger_and_identifier_no_authenticator(self):
        environ = self._makeEnviron()
        headers = [('a', '1')]
        app = DummyWorkingApp('401 Unauthorized', headers)
        from paste.httpexceptions import HTTPUnauthorized
        challenge_app = HTTPUnauthorized()
        challenge = DummyChallenger(challenge_app)
        challengers = [ ('challenge', challenge) ]
        credentials = {'login':'******', 'password':'******'}
        identifier = DummyIdentifier(credentials)
        identifiers = [ ('identifier', identifier) ]
        mw = self._makeOne(app=app, challengers=challengers,
                           identifiers=identifiers)
        start_response = DummyStartResponse()

        result = mw(environ, start_response)
        self.assertEqual(environ['challenged'], challenge_app)
        self.failUnless(result[0].startswith('401 Unauthorized\r\n'))
        self.assertEqual(identifier.forgotten, False)
        self.assertEqual(environ.get('REMOTE_USER'), None)
Ejemplo n.º 23
0
    def authenticate(self, environ, identity):
        # Detect the request type
        rtype = self._detect_request_type(environ, identity)
        # Prepare the common environment for the actions
        env = dict(environ=environ, identity=identity if identity else {})
        failed = False
        # Iterate through the actions of the request type and let them validate
        # and modify the common environment
        for validator in self.request_types[rtype]:
            if not validator(self, env):
                failed = True
                break

        if failed:
            # One validator failed. The failed validator may prevent the 401 if
            # it sets env['throw_401'] = False. If not then DIE!
            throw_401 = env.get('throw_401', True)
            if rtype in ('request-token', 'access-token') and throw_401:
                # repoze will replace the downstream app with what we set in
                # repoze.who.application. This is a standard way to replace the
                # downstream app in IAuthenticators
                environ['repoze.who.application'] = HTTPUnauthorized()

            return

        consumer = env.get('consumer')
        if consumer:
            # If the validators found a consumer then remember it in the environ
            identity['repoze.who.consumerkey'] = consumer.key
            identity['consumer'] = consumer

            token = env.get('token')
            if token:
                # If a token exists then it's a 3-legged request - return the
                # associated userid
                return token.userid
            else:
                # Otherwise it's a 2-legged request - return the consumer key
                return 'consumer:%s' % consumer.key
Ejemplo n.º 24
0
 def test_call_app_doesnt_call_start_response(self):
     environ = self._makeEnviron()
     headers = [('a', '1')]
     app = DummyGeneratorApp('200 OK', headers)
     from paste.httpexceptions import HTTPUnauthorized
     challenge_app = HTTPUnauthorized()
     challenge = DummyChallenger(challenge_app)
     challengers = [ ('challenge', challenge) ]
     credentials = {'login':'******', 'password':'******'}
     identifier = DummyIdentifier(credentials)
     identifiers = [ ('identifier', identifier) ]
     authenticator = DummyAuthenticator()
     authenticators = [ ('authenticator', authenticator) ]
     mdprovider = DummyMDProvider({'foo':'bar'})
     mdproviders = [ ('mdprovider', mdprovider) ]
     mw = self._makeOne(app=app, challengers=challengers,
                        identifiers=identifiers,
                        authenticators=authenticators,
                        mdproviders=mdproviders)
     start_response = DummyStartResponse()
     result = mw(environ, start_response)
     # metadata
     self.assertEqual(environ['repoze.who.identity']['foo'], 'bar')
Ejemplo n.º 25
0
    def test_call_200_challenger_and_identifier_and_authenticator(self):
        environ = self._makeEnviron()
        headers = [('a', '1')]
        app = DummyWorkingApp('200 OK', headers)
        from paste.httpexceptions import HTTPUnauthorized
        challenge_app = HTTPUnauthorized()
        challenge = DummyChallenger(challenge_app)
        challengers = [ ('challenge', challenge) ]
        credentials = {'login':'******', 'password':'******'}
        identifier = DummyIdentifier(credentials)
        identifiers = [ ('identifier', identifier) ]
        authenticator = DummyAuthenticator()
        authenticators = [ ('authenticator', authenticator) ]
        mw = self._makeOne(app=app, challengers=challengers,
                           identifiers=identifiers,
                           authenticators=authenticators)
        start_response = DummyStartResponse()
        result = mw(environ, start_response)
        self.assertEqual(environ.get('challenged'), None)
        self.assertEqual(identifier.forgotten, False)
        # @@ figure out later
##         self.assertEqual(dict(identifier.remembered)['login'], dict(identifier.credentials)['login'])
##         self.assertEqual(dict(identifier.remembered)['password'], dict(identifier.credentials)['password'])
        self.assertEqual(environ['REMOTE_USER'], 'chris')
            log.error('The requesting Relying Party requires additional '
                      'attributes which this site isn\'t configured to '
                      'provide.')
            raise HTTPUnauthorized()

        except OpenIDProviderReloginRequired, e:
            log.error('An error occurred setting return attribute parameters '
                      'required by the Relying Party requesting your ID.')
            raise HTTPUnauthorized()

        except Exception, e:
            log.error(
                "%s type exception raised setting additional attributes "
                " in the response: %s", e.__class__.__name__,
                traceback.format_exc())
            raise HTTPUnauthorized()

        webresponse = self.oidserver.encodeResponse(oid_response)
        hdr = webresponse.headers.items()

        # If the content length exceeds the maximum to represent on a URL,
        # it's rendered as a form instead
        # FIXME: Got rid out oid_response.renderAsForm() test as it doesn't
        # give consistent answers.
        #
        # The FORM_MATCH_TEXT test detects whether the response needs to be
        # wrapped in the FORM_RESP_WRAPPER_TMPL Javascript.  This is only
        # needed when this Provider is return key/values pairs back to the
        # RP as a POST'ed form
        if webresponse.body.startswith(
                OpenIDProviderMiddleware.FORM_MATCH_TEXT):
Ejemplo n.º 27
0
 def build_authentication(self):
     head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
     return HTTPUnauthorized(headers=head)
Ejemplo n.º 28
0
 def challenge(self, environ, status, app_headers, forget_headers):
     head = self._get_wwwauth()
     if head[0] not in forget_headers:
         head = head + forget_headers
     return HTTPUnauthorized(headers=head)
Ejemplo n.º 29
0
 def challenge(self, environ, status, app_headers, forget_headers):
     return HTTPUnauthorized()
Ejemplo n.º 30
0
    def __call__(self, environ, start_response):
        """Authenticate based HTTP header elements as specified by the HTTP
        Basic Authentication spec.
        
        @param environ: WSGI environ 
        @type environ: dict-like type
        @param start_response: WSGI start response function
        @type start_response: function
        @return: response
        @rtype: iterable
        @raise HttpBasicAuthMiddlewareConfigError: no authentication callback
        found in environ
        """
        log.debug("HttpBasicAuthNMiddleware.__call__ ...")

        if (not self._path_match(environ)
                or not self._http_hdr_field_match(environ)):
            return self.__app(environ, start_response)

        # Pick up authentication callback from local variable or special key
        # in environ set by upstream middleware
        if self.authentication_callback is None:
            authenticate_func = environ.get(self.authn_func_environ_keyname)
        else:
            authenticate_func = self.authentication_callback

        if authenticate_func is None:
            # HTTP 500 default is right for this error
            raise HttpBasicAuthMiddlewareConfigError("No authentication "
                                                     "function set in environ")

        def start_response_wrapper(status, headers, exec_info=None):
            """Ensure Authentication realm is included with 401 responses"""
            status_code = int(status.split()[0])
            if status_code == httplib.UNAUTHORIZED:
                authn_realm_hdrFound = False
                for name, val in headers:
                    if (name.lower() ==
                            self.__class__.AUTHENTICATE_HDR_FIELDNAME_LOWER):
                        authn_realm_hdrFound = True
                        break

                if not authn_realm_hdrFound:
                    # Nb. realm requires double quotes according to RFC
                    authn_realm_hdr = (
                        self.__class__.AUTHENTICATE_HDR_FIELDNAME,
                        self.__class__.AUTHN_HDR_FORMAT %
                        (self.__class__.AUTHN_SCHEME_HDR_FIELDNAME,
                         self.realm))
                    headers.append(authn_realm_hdr)

            return start_response(status, headers)

        username, password = self.parse_credentials(environ)

        # Call authentication middleware/application.
        try:
            response = authenticate_func(environ, start_response_wrapper,
                                         username, password)
        except HTTPUnauthorized:
            if username is None:
                # If no username is set, set the HTTP Basic Auth challenge
                # returning an auth realm
                log.error('No username set in HTTP Authorization header')
                http_unauthorized = HTTPUnauthorized("No username set")

                return http_unauthorized(environ, start_response_wrapper)
            else:
                # Credentials were set it's just they were invalid
                raise

        except HTTPException, e:
            return e(environ, start_response)
Ejemplo n.º 31
0
    def _complete_login(self, environ, start_response):
        """Complete the OpenID authentication process.

        Here we handle the result of the OpenID process.  If the process
        succeeded, we record the username in the session and redirect the user
        to the page they were trying to view that triggered the login attempt.
        In the various failures cases we return a 401 Unauthorized response
        with a brief explanation of what went wrong.
        """
        query = dict(parse_querystring(environ))
        # Passing query['openid.return_to'] here is massive cheating, but
        # given we control the endpoint who cares.
        response = self._make_consumer(environ).complete(
            query, query['openid.return_to'])
        if response.status == SUCCESS:
            self.log.error('open id response: SUCCESS')
            sreg_info = SRegResponse.fromSuccessResponse(response)
            if not sreg_info:
                self.log.error('sreg_info is None.')
                exc = HTTPUnauthorized()
                exc.explanation = (
                    "You don't have a Launchpad account. Check that you're "
                    "logged in as the right user, or log into Launchpad and try "
                    "again.")
                raise exc
            environ[self.session_var]['identity_url'] = response.identity_url
            environ[self.session_var]['user'] = sreg_info['nickname']
            raise HTTPMovedPermanently(query['back_to'])
        elif response.status == FAILURE:
            self.log.error('open id response: FAILURE: %s', response.message)
            exc = HTTPUnauthorized()
            exc.explanation = response.message
            raise exc
        elif response.status == CANCEL:
            self.log.error('open id response: CANCEL')
            exc = HTTPUnauthorized()
            exc.explanation = "Authentication cancelled."
            raise exc
        else:
            self.log.error('open id response: UNKNOWN')
            exc = HTTPUnauthorized()
            exc.explanation = "Unknown OpenID response."
            raise exc
Ejemplo n.º 32
0
    def __call__(self, environ, start_response):
        request_is_private = (environ['SERVER_PORT'] == str(
            config.codebrowse.private_port))
        environ['loggerhead.static.url'] = environ['SCRIPT_NAME']
        if environ['PATH_INFO'].startswith('/static/'):
            path_info_pop(environ)
            return static_app(environ, start_response)
        elif environ['PATH_INFO'] == '/favicon.ico':
            return favicon_app(environ, start_response)
        elif environ['PATH_INFO'] == '/robots.txt':
            return robots_app(environ, start_response)
        elif not request_is_private:
            if environ['PATH_INFO'].startswith('/+login'):
                return self._complete_login(environ, start_response)
            elif environ['PATH_INFO'].startswith('/+logout'):
                return self._logout(environ, start_response)
        path = environ['PATH_INFO']
        trailingSlashCount = len(path) - len(path.rstrip('/'))
        if request_is_private:
            # Requests on the private port are internal API requests from
            # something that has already performed security checks.  As
            # such, they get read-only access to everything.
            identity_url = LAUNCHPAD_SERVICES
            user = LAUNCHPAD_SERVICES
        else:
            identity_url = environ[self.session_var].get(
                'identity_url', LAUNCHPAD_ANONYMOUS)
            user = environ[self.session_var].get('user', LAUNCHPAD_ANONYMOUS)
        lp_server = get_lp_server(identity_url,
                                  branch_transport=self.get_transport())
        lp_server.start_server()
        try:

            try:
                branchfs = self.get_branchfs()
                transport_type, info, trail = branchfs.translatePath(
                    identity_url, urlutils.escape(path))
            except xmlrpclib.Fault as f:
                if check_fault(f, faults.PathTranslationError):
                    raise HTTPNotFound()
                elif check_fault(f, faults.PermissionDenied):
                    # If we're not allowed to see the branch...
                    if environ['wsgi.url_scheme'] != 'https':
                        # ... the request shouldn't have come in over http, as
                        # requests for private branches over http should be
                        # redirected to https by the dynamic rewrite script we
                        # use (which runs before this code is reached), but
                        # just in case...
                        env_copy = environ.copy()
                        env_copy['wsgi.url_scheme'] = 'https'
                        raise HTTPMovedPermanently(construct_url(env_copy))
                    elif user != LAUNCHPAD_ANONYMOUS:
                        # ... if the user is already logged in and still can't
                        # see the branch, they lose.
                        exc = HTTPUnauthorized()
                        exc.explanation = "You are logged in as %s." % user
                        raise exc
                    else:
                        # ... otherwise, lets give them a chance to log in
                        # with OpenID.
                        return self._begin_login(environ, start_response)
                else:
                    raise
            if transport_type != BRANCH_TRANSPORT:
                raise HTTPNotFound()
            trail = urlutils.unescape(trail).encode('utf-8')
            trail += trailingSlashCount * '/'
            amount_consumed = len(path) - len(trail)
            consumed = path[:amount_consumed]
            branch_name = consumed.strip('/')
            self.log.info('Using branch: %s', branch_name)
            if trail and not trail.startswith('/'):
                trail = '/' + trail
            environ['PATH_INFO'] = trail
            environ['SCRIPT_NAME'] += consumed.rstrip('/')
            branch_url = lp_server.get_url() + branch_name
            branch_link = urlparse.urljoin(config.codebrowse.launchpad_root,
                                           branch_name)
            cachepath = os.path.join(config.codebrowse.cachepath,
                                     branch_name[1:])
            if not os.path.isdir(cachepath):
                os.makedirs(cachepath)
            self.log.info('branch_url: %s', branch_url)
            private = info['private']
            if private:
                self.log.info("Branch is private")
            else:
                self.log.info("Branch is public")

            try:
                bzr_branch = safe_open(lp_server.get_url().strip(':/'),
                                       branch_url)
            except errors.NotBranchError as err:
                self.log.warning('Not a branch: %s', err)
                raise HTTPNotFound()
            bzr_branch.lock_read()
            try:
                view = BranchWSGIApp(bzr_branch,
                                     branch_name, {'cachepath': cachepath},
                                     self.graph_cache,
                                     branch_link=branch_link,
                                     served_url=None,
                                     private=private)
                return view.app(environ, start_response)
            finally:
                bzr_branch.repository.revisions.clear_cache()
                bzr_branch.repository.signatures.clear_cache()
                bzr_branch.repository.inventories.clear_cache()
                if bzr_branch.repository.chk_bytes is not None:
                    bzr_branch.repository.chk_bytes.clear_cache()
                bzr_branch.repository.texts.clear_cache()
                bzr_branch.unlock()
        finally:
            lp_server.stop_server()
Ejemplo n.º 33
0
    def __call__(self, environ, start_response):
        environ['loggerhead.static.url'] = environ['SCRIPT_NAME']
        if environ['PATH_INFO'].startswith('/static/'):
            path_info_pop(environ)
            return static_app(environ, start_response)
        elif environ['PATH_INFO'] == '/favicon.ico':
            return favicon_app(environ, start_response)
        elif environ['PATH_INFO'] == '/robots.txt':
            return robots_app(environ, start_response)
        elif environ['PATH_INFO'].startswith('/+login'):
            return self._complete_login(environ, start_response)
        elif environ['PATH_INFO'].startswith('/+logout'):
            return self._logout(environ, start_response)
        path = environ['PATH_INFO']
        trailingSlashCount = len(path) - len(path.rstrip('/'))
        user = environ[self.session_var].get('user', LAUNCHPAD_ANONYMOUS)
        lp_server = get_lp_server(user, branch_transport=self.get_transport())
        lp_server.start_server()
        try:

            try:
                transport_type, info, trail = self.branchfs.translatePath(
                    user, urlutils.escape(path))
            except xmlrpclib.Fault as f:
                if check_fault(f, faults.PathTranslationError):
                    raise HTTPNotFound()
                elif check_fault(f, faults.PermissionDenied):
                    # If we're not allowed to see the branch...
                    if environ['wsgi.url_scheme'] != 'https':
                        # ... the request shouldn't have come in over http, as
                        # requests for private branches over http should be
                        # redirected to https by the dynamic rewrite script we
                        # use (which runs before this code is reached), but
                        # just in case...
                        env_copy = environ.copy()
                        env_copy['wsgi.url_scheme'] = 'https'
                        raise HTTPMovedPermanently(construct_url(env_copy))
                    elif user != LAUNCHPAD_ANONYMOUS:
                        # ... if the user is already logged in and still can't
                        # see the branch, they lose.
                        exc = HTTPUnauthorized()
                        exc.explanation = "You are logged in as %s." % user
                        raise exc
                    else:
                        # ... otherwise, lets give them a chance to log in
                        # with OpenID.
                        return self._begin_login(environ, start_response)
                else:
                    raise
            if transport_type != BRANCH_TRANSPORT:
                raise HTTPNotFound()
            trail = urlutils.unescape(trail).encode('utf-8')
            trail += trailingSlashCount * '/'
            amount_consumed = len(path) - len(trail)
            consumed = path[:amount_consumed]
            branch_name = consumed.strip('/')
            self.log.info('Using branch: %s', branch_name)
            if trail and not trail.startswith('/'):
                trail = '/' + trail
            environ['PATH_INFO'] = trail
            environ['SCRIPT_NAME'] += consumed.rstrip('/')
            branch_url = lp_server.get_url() + branch_name
            branch_link = urlparse.urljoin(
                config.codebrowse.launchpad_root, branch_name)
            cachepath = os.path.join(
                config.codebrowse.cachepath, branch_name[1:])
            if not os.path.isdir(cachepath):
                os.makedirs(cachepath)
            self.log.info('branch_url: %s', branch_url)
            base_api_url = allvhosts.configs['api'].rooturl
            branch_api_url = '%s/%s/%s' % (
                base_api_url,
                'devel',
                branch_name,
                )
            self.log.info('branch_api_url: %s', branch_api_url)
            req = urllib2.Request(branch_api_url)
            private = False
            try:
                # We need to determine if the branch is private
                response = urllib2.urlopen(req)
            except urllib2.HTTPError as response:
                code = response.getcode()
                if code in (400, 401, 403, 404):
                    # There are several error codes that imply private data.
                    # 400 (bad request) is a default error code from the API
                    # 401 (unauthorized) should never be returned as the
                    # requests are always from anon. If it is returned
                    # however, the data is certainly private.
                    # 403 (forbidden) is obviously private.
                    # 404 (not found) implies privacy from a private team or
                    # similar situation, which we hide as not existing rather
                    # than mark as forbidden.
                    self.log.info("Branch is private")
                    private = True
                self.log.info(
                    "Branch state not determined; api error, return code: %s",
                    code)
                response.close()
            else:
                self.log.info("Branch is public")
                response.close()

            try:
                bzr_branch = safe_open(
                    lp_server.get_url().strip(':/'), branch_url)
            except errors.NotBranchError as err:
                self.log.warning('Not a branch: %s', err)
                raise HTTPNotFound()
            bzr_branch.lock_read()
            try:
                view = BranchWSGIApp(
                    bzr_branch, branch_name, {'cachepath': cachepath},
                    self.graph_cache, branch_link=branch_link,
                    served_url=None, private=private)
                return view.app(environ, start_response)
            finally:
                bzr_branch.repository.revisions.clear_cache()
                bzr_branch.repository.signatures.clear_cache()
                bzr_branch.repository.inventories.clear_cache()
                if bzr_branch.repository.chk_bytes is not None:
                    bzr_branch.repository.chk_bytes.clear_cache()
                bzr_branch.repository.texts.clear_cache()
                bzr_branch.unlock()
        finally:
            lp_server.stop_server()