Esempio n. 1
0
    def dispatch(self):
        """Dispatches the requested method."""

        request = self.request
        method_name = request.route.handler_method
        if not method_name:
            method_name = webapp2._normalize_handler_method(request.method)

        method = getattr(self, method_name, None)
        if method is None:
            # 405 Method Not Allowed.
            # The response MUST include an Allow header containing a
            # list of valid methods for the requested resource.
            # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.6
            valid = ', '.join(webapp2._get_handler_methods(self))
            self.abort(405, headers=[('Allow', valid)])

        # The handler only receives *args if no named variables are set.
        args, kwargs = request.route_args, request.route_kwargs
        if kwargs:
            args = ()

        # bind session on dispatch (not in __init__)
        self.session = get_current_session()
        # init messages array based on session
        self.session['_gaetk_messages'] = self.session.get('_gaetk_messages', [])
        # Give authentication Hooks opportunity to do their thing
        self.authchecker(method, *args, **kwargs)

        # Execute the method.
        reply = method(*args, **kwargs)

        # find out which return convention was used - first set defaults ...
        content = reply
        statuscode = 200
        cachingtime = self.default_cachingtime
        # ... then check if we got a 2-tuple reply ...
        if isinstance(reply, tuple) and len(reply) == 2:
            content, statuscode = reply
        # ... or a 3-tuple reply.
        if isinstance(reply, tuple) and len(reply) == 3:
            content, statuscode, cachingtime = reply
        # Finally begin sending the response
        response = self.serialize(content)
        if cachingtime:
            self.response.headers['Cache-Control'] = 'max-age=%d, public' % cachingtime
        # If we have gotten a `callback` parameter, we expect that this is a
        # [JSONP](http://en.wikipedia.org/wiki/JSONP#JSONP) cann and therefore add the padding
        if self.request.get('callback', None):
            response = "%s (%s)" % (self.request.get('callback', None), response)
            self.response.headers['Content-Type'] = 'text/javascript'
        else:
            self.response.headers['Content-Type'] = 'application/json'
        # Set status code and write JSON to output stream
        self.response.set_status(statuscode)
        self.response.out.write(response)
        self.response.out.write('\n')
Esempio n. 2
0
    def __init__(self, *args, **kwargs):
        """Initialize handler instance"""

        super(OpenIdLoginHandler, self).__init__(*args, **kwargs)

        # clean previous session
        self.session = get_current_session()
        self.session.regenerate_id()
        if self.session.is_active():
            self.session.terminate()
Esempio n. 3
0
 def __init__(self, *args, **kwargs):
     """Initialize RequestHandler"""
     self.credential = None
     try:
         self.session = get_current_session()
     except AttributeError:
         # session middleware might not be enabled
         self.session = {}
     super(BasicHandler, self).__init__(*args, **kwargs)
     self.credential = None
Esempio n. 4
0
    def login_required(self):
        """Returns the currently logged in user."""
        self.session = get_current_session()
        self.credential = None
        if self.session.get('uid'):
            self.credential = memcache.get("cred_%s" % self.session['uid'])
            if self.credential is None:
                self.credential = Credential.get_by_key_name(self.session['uid'])
                memcache.add("cred_%s" % self.session['uid'], self.credential, CRED_CACHE_TIMEOUT)

        # we don't have an active session
        if not self.credential:
            # no session information - try HTTP - Auth
            uid, secret = None, None
            # see if we have HTTP-Basic Auth Data
            if self.request.headers.get('Authorization'):
                auth_type, encoded = self.request.headers.get('Authorization').split(None, 1)
                if auth_type.lower() == 'basic':
                    uid, secret = encoded.decode('base64').split(':', 1)
                    credential = memcache.get("cred_%s" % uid)
                    if not credential:
                        credential = Credential.get_by_key_name(uid.strip() or ' *invalid* ')
                        memcache.add("cred_%s" % uid, credential, CRED_CACHE_TIMEOUT)
                    if credential and credential.secret == secret.strip():
                        # Successful login
                        self.credential = credential
                        self.session['uid'] = credential.uid
                        # Log, but only once every 10h
                        data = memcache.get("login_%s_%s" % (uid, self.request.remote_addr))
                        if not data:
                            memcache.set("login_%s_%s" % (uid, self.request.remote_addr), True, 60 * 60 * 10)
                            logging.info("HTTP-Login from %s/%s", uid, self.request.remote_addr)
                    else:
                        logging.error("failed HTTP-Login from %s/%s %s", uid, self.request.remote_addr,
                                       self.request.headers.get('Authorization'))
                else:
                    logging.error("unknown HTTP-Login type %r %s %s", auth_type, self.request.remote_addr,
                                   self.request.headers.get('Authorization'))

        # HTTP Basic Auth failed
        if not self.credential:
            # Login not successfull
            if 'text/html' in self.request.headers.get('Accept', ''):
                # we assume the request came via a browser - redirect to the "nice" login page
                self.response.set_status(302)
                absolute_url = self.abs_url("/_ah/login_required?continue=%s" % urllib.quote(self.request.url))
                self.response.headers['Location'] = str(absolute_url)
                raise HTTP302_Found(location=str(absolute_url))
            else:
                # We assume the access came via cURL et al, request Auth vie 401 Status code.
                logging.debug("requesting HTTP-Auth %s %s", self.request.remote_addr,
                              self.request.headers.get('Authorization'))
                raise HTTP401_Unauthorized(headers={'WWW-Authenticate': 'Basic realm="API Login"'})

        return self.credential
Esempio n. 5
0
 def get(self):
     session = get_current_session()
     session['uid'] = None
     if session.is_active():
         session.terminate()
     # log out OpenID
     user = users.get_current_user()
     if user:
         self.redirect(users.create_logout_url("/logout"))
     else:
         # Render Template with logout confirmation
         self.render({}, 'logout.html')
Esempio n. 6
0
def get_current_user():
    """Helper function to return a valid User instance.

    For users logged in via OpenID, the result is equivalent to users.get_current_user.
    If the user logged in via Basic Auth, the user id is taken from the related Credential object.
    """
    user = users.get_current_user()
    if user is not None:
        return user
    else:
        session = get_current_session()
        if session and 'uid' in session:
            return users.User(_user_id=session['uid'], email=session.get('email', ''), _strict_mode=False)
Esempio n. 7
0
    def get(self):
        session = get_current_session()
        session['uid'] = None
        if session.is_active():
            session.terminate()

        # log out OpenID and either redirect to 'continue' or display
        # the default logout confirmation page
        continue_url = self.request.get('continue')
        user = users.get_current_user()
        if user:
            self.redirect(users.create_logout_url(continue_url or '/logout'))
        else:
            # render template with logout confirmation
            if continue_url:
                self.redirect(continue_url)
            else:
                self.render({}, 'logout.html')
Esempio n. 8
0
    def get(self):
        """Logout user and terminate the current session"""

        session = get_current_session()
        session['uid'] = None
        if session.is_active():
            session.terminate()

        # log out OpenID and either redirect to 'continue' or display
        # the default logout confirmation page
        continue_url = self.request.get('continue')

        user = users.get_current_user()
        if user:
            path = self.request.path
            self.redirect(users.create_logout_url(path))
        else:
            if continue_url:
                self.redirect(continue_url)
            else:
                self.render({}, 'logout.html')
Esempio n. 9
0
    def dispatch(self):
        """Dispatches the requested method."""
        request = self.request
        method_name = request.route.handler_method
        if not method_name:
            method_name = webapp2._normalize_handler_method(request.method)

        method = getattr(self, method_name, None)
        if method is None:
            # 405 Method Not Allowed.
            # The response MUST include an Allow header containing a
            # list of valid methods for the requested resource.
            # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.6
            methods = []
            for method in ('GET', 'POST', 'HEAD', 'OPTIONS', 'PUT', 'DELETE', 'TRACE'):
                if getattr(self, webapp2._normalize_handler_method(method), None):
                    methods.append(method)
            valid = ', '.join(methods)
            self.abort(405, headers=[('Allow', valid)])

        # The handler only receives *args if no named variables are set.
        args, kwargs = request.route_args, request.route_kwargs
        if kwargs:
            args = ()

        # bind session on dispatch (not in __init__)
        try:
            self.session = get_current_session()
        except AttributeError:
            # session handling not activated
            self.session = {}
        # init messages array based on session
        self.session['_gaetk_messages'] = self.session.get('_gaetk_messages', [])
        # Give authentication Hooks opportunity to do their thing
        self.authchecker(method, *args, **kwargs)

        ret = method(*args, **kwargs)
        self.finished_hook(ret, method, *args, **kwargs)
        return ret
Esempio n. 10
0
    def dispatch(self):
        """Dispatches the requested method fom the WSGI App.

        Meant for internal use by the stack.
        """
        request = self.request
        method_name = request.route.handler_method
        if not method_name:
            method_name = webapp2._normalize_handler_method(request.method)

        method = getattr(self, method_name, None)
        if hasattr(self, '__class__'):
            sentry_client.tags_context({
                'handler': self.__class__.__name__,
                'method': method_name
            })

        if method is None:
            # 405 Method Not Allowed.
            valid = b', '.join(webapp2._get_handler_methods(self))
            raise exc.HTTP405_HTTPMethodNotAllowed(
                'Method not allowed in {}'.format(self.__class__.__name__),
                headers=[(b'Allow', valid)],
            )

        # The handler only receives *args if no named variables are set.
        args, kwargs = request.route_args, request.route_kwargs
        if kwargs:
            args = ()

        # bind session on dispatch (not in __init__)
        try:
            self.session = gaesessions.get_current_session()
        except AttributeError:
            # probably session middleware not loaded
            self.session = {}

        if str(self.session) != 'uninitialized session':
            sentry_client.note('storage',
                               'Session loaded',
                               data=dict(session=self.session))

        try:
            self._call_all_inherited('pre_authentication_hook', method_name,
                                     *args, **kwargs)
            self._call_all_inherited('authentication_preflight_hook',
                                     method_name, *args, **kwargs)
            self._call_all_inherited('authentication_hook', method_name, *args,
                                     **kwargs)
            self._call_all_inherited('authorisation_hook', method_name, *args,
                                     **kwargs)
            self._call_all_inherited('method_preperation_hook', method_name,
                                     *args, **kwargs)
            try:
                response = method(*args, **kwargs)
            except TypeError:
                # parameter missmatch is the error we see most often
                # so help to pin down where it happens
                klass = introspection.get_class_that_defined_method(method)
                methname = method.__name__
                sourcepos = '{}:{}'.format(
                    os.path.basename(method.__func__.__code__.co_filename),
                    method.__func__.__code__.co_firstlineno,
                )
                LOGGER.debug(
                    'method called: %s.%s(%r) from %s',
                    klass.__name__,
                    methname,
                    (args, kwargs),
                    sourcepos,
                )
                LOGGER.debug('defined at: %s %s', klass, sourcepos)
                raise
            response = self.response_overwrite(response, method, *args,
                                               **kwargs)
        except exc.HTTPException as e:
            # for HTTP exceptions execute `finished_hooks`
            if e.code < 500:
                self._call_all_inherited('finished_hook', method_name, *args,
                                         **kwargs)
            return self.handle_exception(e, self.app.debug)
        except BaseException as e:
            return self.handle_exception(e, self.app.debug)

        if response and not getattr(self, '_gaetk2_allow_strange_responses',
                                    False):
            assert isinstance(response, webapp2.Response)

        self._set_cache_headers()
        self._call_all_inherited('finished_hook', method_name, *args, **kwargs)
        self.finished_overwrite(response, method, *args, **kwargs)
        return response
Esempio n. 11
0
    def login_required(self, deny_localhost=True):
        """Returns the currently logged in user and forces login.

        Access from 127.0.0.1 is allowed without authentication if deny_localhost is false.
        """

        self.session = get_current_session()
        self.credential = None
        if self.session.get('uid'):
            self.credential = memcache.get("cred_%s" % self.session['uid'])
            if self.credential is None:
                self.credential = Credential.get_by_key_name(self.session['uid'])
                memcache.add("cred_%s" % self.session['uid'], self.credential, CREDENTIAL_CACHE_TIMEOUT)

        # we don't have an active session - check if we are logged in via OpenID at least
        user = users.get_current_user()
        if user:
            logging.info('Google user = %s', user)
            # yes, active OpenID session
            # user.federated_provider() == 'https://www.google.com/a/hudora.de/o8/ud?be=o8'
            if not user.federated_provider():
                # development server
                apps_domain = user.email().split('@')[-1].lower()
            else:
                apps_domain = user.federated_provider().split('/')[4].lower()
            username = user.email()
            self.credential = Credential.get_by_key_name(username)
            if not self.credential or not self.credential.uid == username:
                # So far we have no Credential entity for that user, create one
                if getattr(config, 'LOGIN_OPENID_CREDENTIAL_CREATOR', None):
                    self.credential = config.LOGIN_OPENID_CREDENTIAL_CREATOR(user, apps_domain)
                if not self.credential:
                    self.credential = create_credential_from_federated_login(user, apps_domain)
            self.session['uid'] = self.credential.uid
            # self.response.set_cookie('gaetk_opid', apps_domain, max_age=60*60*24*90)
            self.response.headers['Set-Cookie'] = 'gaetk_opid=%s; Max-Age=7776000' % apps_domain

        if not self.credential:
            # still no session information - try HTTP - Auth
            uid, secret = None, None
            # see if we have HTTP-Basic Auth Data
            if self.request.headers.get('Authorization'):
                auth_type, encoded = self.request.headers.get('Authorization').split(None, 1)
                if auth_type.lower() == 'basic':
                    decoded = encoded.decode('base64')
                    # If the Client send us invalid credentials, let him know , else parse into
                    # username and password
                    if ':' not in decoded:
                        raise HTTP400_BadRequest("invalid credentials %r" % decoded)
                    uid, secret = decoded.split(':', 1)
                    # Pull credential out of memcache or datastore
                    credential = memcache.get("cred_%s" % uid)
                    if not credential:
                        credential = Credential.get_by_key_name(uid.strip() or ' *invalid* ')
                        memcache.add("cred_%s" % uid, credential, CREDENTIAL_CACHE_TIMEOUT)
                    if credential and credential.secret == secret.strip():
                        # Successful login
                        self.credential = credential
                        self.session['uid'] = credential.uid
                        # Log successful login, but only once every 10h
                        data = memcache.get("login_%s_%s" % (uid, self.request.remote_addr))
                        if not data:
                            memcache.set("login_%s_%s" % (uid, self.request.remote_addr), True, 60 * 60 * 10)
                            logging.info("HTTP-Login from %s/%s", uid, self.request.remote_addr)
                    else:
                        logging.error("failed HTTP-Login from %s/%s %s", uid, self.request.remote_addr,
                                       self.request.headers.get('Authorization'))
                else:
                    logging.error("unknown HTTP-Login type %r %s %s", auth_type, self.request.remote_addr,
                                   self.request.headers.get('Authorization'))

        # HTTP Basic Auth failed
        if not self.credential:
            if (self.request.remote_addr == '127.0.0.1') and not deny_localhost:
                logging.info('for testing we allow unauthenticated access from localhost')
                # create credential
                self.credential = Credential.create(tenant='localhost.', uid='0x7f000001',
                                                    text='Automatically created for testing')
            else:
                # Login not successful
                if 'text/html' in self.request.headers.get('Accept', ''):
                    # we assume the request came via a browser - redirect to the "nice" login page
                    self.response.set_status(302)
                    absolute_url = self.abs_url("/_ah/login_required?continue=%s" % urllib.quote(self.request.url))
                    self.response.headers['Location'] = str(absolute_url)
                    raise HTTP302_Found(location=str(absolute_url))
                else:
                    # We assume the access came via cURL et al, request Auth vie 401 Status code.
                    logging.info("requesting HTTP-Auth %s %s", self.request.remote_addr,
                                  self.request.headers.get('Authorization'))
                    raise HTTP401_Unauthorized(headers={'WWW-Authenticate': 'Basic realm="API Login"'})

        return self.credential
Esempio n. 12
0
    def get(self):
        """Handler for Federated login consumer (OpenID) AND HTTP-Basic-Auth.

        See http://code.google.com/appengine/articles/openid.html"""

        msg = ''
        continue_url = self.request.GET.get('continue', '/')
        openid_url = None
        session = get_current_session()
        # clean previous session
        if session.is_active():
            session.terminate()

        # check if we are logged in via OpenID
        user = users.get_current_user()
        if user:
            logging.info('Google user = %s', user)
            # yes, active OpenID session
            # user.federated_provider() == 'https://www.google.com/a/hudora.de/o8/ud?be=o8'
            if not user.federated_provider():
                # development server
                apps_domain = user.email().split('@')[-1].lower()
            else:
                apps_domain = user.federated_provider().split('/')[4].lower()
            username = user.email()
            credential = Credential.get_by_key_name(username)
            if not credential or not credential.uid == username:
                # So far we have no Credential entity for that user, create one
                if getattr(config, 'LOGIN_OPENID_CREDENTIAL_CREATOR', None):
                    self.credential = config.LOGIN_OPENID_CREDENTIAL_CREATOR(user, apps_domain)
                if not self.credential:
                    self.credential = create_credential_from_federated_login(user, apps_domain)
            session['uid'] = credential.uid
            # self.response.set_cookie('gaetk_opid', apps_domain, max_age=60*60*24*90)
            self.response.headers['Set-Cookie'] = 'gaetk_opid=%s; Max-Age=7776000' % apps_domain
            self.redirect(continue_url)
            return

        # we returned from the login form - did the user request OpenID login?
        for domain in ALLOWED_DOMAINS:
            if self.request.GET.get('%s.x' % domain):
                openid_url = 'https://www.google.com/accounts/o8/site-xrds?hd=%s' % domain
        if openid_url:
            logging.info("Openid login requested to %s", openid_url)

        if openid_url:
            # Hand over Authentication Processing to Google/OpenID
            self.redirect(users.create_login_url(continue_url, None, openid_url))
            return
        else:
            # Try user:pass based Authentication
            username, password = None, None
            # see if we have HTTP-Basic Auth Data
            if self.request.headers.get('Authorization'):
                auth_type, encoded = self.request.headers.get('Authorization').split(None, 1)
                if auth_type.lower() == 'basic':
                    username, password = encoded.decode('base64').split(':', 1)

            # see if we have gotten some Form Data instead
            if not (username and password):
                username = self.request.get('username').strip()
                password = self.request.get('password').strip()

            # verify user & password
            if username:
                logging.info("Login Attempt for %s", username)
                credential = Credential.get_by_key_name(username)
                if credential and credential.secret == password:
                    # successfull login
                    session['uid'] = credential.uid
                    # redirect back where we came from
                    logging.info("Login durch %s/%s, Umleitung zu %s", username, self.request.remote_addr,
                                 continue_url)
                    self.redirect(continue_url)
                    return
                else:
                    logging.warning("Invalid Password for %s:%s", username, password)
                    msg = 'Kann sie nicht anmelden'

            # Render Template with Login form
            self.render({'continue': continue_url, 'domains': ALLOWED_DOMAINS, 'msg': msg}, 'login.html')