def get(self, kind, objectid):
        """Handler, der die richtige Methode für die Aktion aufruft"""

        admin_class = check404(gaetk2.admin.site.get_admin_by_kind(kind))
        obj = check404(admin_class.get_object(objectid))
        self.render({
            'obj': obj,
            'admin_class': admin_class
        }, 'admin2/detail.html')
    def get(self, kind):

        admin_class = check404(gaetk2.admin.site.get_admin_by_kind(kind))
        model_class = check404(gaetk2.admin.site.get_model_by_kind(kind))

        # unsupported: Link-Fields (oder wie das heißt)
        # unsupported: callables in List_fields
        query = admin_class.get_queryset(self.request)
        template_values = self.paginate(query,
                                        defaultcount=admin_class.list_per_page,
                                        datanodename='object_list',
                                        calctotal=False)
        template_values.update(qtype=self.request.get('qtype'),
                               admin_class=admin_class,
                               model_class=model_class)
        self.render(template_values, 'admin2/list.html')
    def get(self, kind, action_or_objectid):
        """Handler, der die richtige Methode für die Aktion aufruft"""

        admin_class = check404(gaetk2.admin.site.get_admin_by_kind(kind))
        # Bestimme Route! Da könnte man dann auch einen Handler mit angeben.
        # Das muss irgendwie besser gehen als Keys und Actions zu mischen.
        if action_or_objectid == 'add':
            if admin_class.read_only:
                raise exc.HTTP403_Forbidden
            admin_class.add_view(self)
        elif action_or_objectid == 'delete':
            if admin_class.read_only:
                raise exc.HTTP403_Forbidden
            elif not admin_class.deletable:
                raise exc.HTTP403_Forbidden
            else:
                admin_class.delete_view(self)
        else:
            if admin_class.read_only:
                raise exc.HTTP403_Forbidden
            # TODO: view only is missing
            admin_class.change_view(
                self, action_or_objectid,
                extra_context=dict(app=application))  # model=model
    def authentication_preflight_hook(self, method, *args, **kwargs):
        """Find out if the User is authenticated in any sane way and if so load the credential."""
        # Automatically called by `dispatch`.
        # This funcion is somewhat involved. We accept
        # 1) Authentication via HTTP-Auth
        # 2) Authentication via JWT
        # 3) Check for App Engine / Google Apps based Login
        # 4) Authentication via Session
        # 6) Other App Engine Apps
        # 7) log in by Sentry bot
        # 8) Our Test Framework
        self.credential = None
        uid, secret = None, None
        # 1. Check for valid HTTP-Basic Auth Login
        if self.request.headers.get('Authorization',
                                    '').lower().startswith('basic '):
            auth_type, encoded = self.request.headers.get(
                'Authorization').split(None, 1)
            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 exc.HTTP400_BadRequest(
                    explanation='invalid credentials %r' % decoded)
            uid, secret = decoded.strip().split(':', 1)
            sentry_client.note('user',
                               'HTTP-Auth attempted for %r' % uid,
                               data=dict(auth_typ=auth_type, decoded=decoded))

            self.credential = self.get_credential(uid or ' *invalid* ')
            if self.credential and self.credential.secret == secret.strip():
                # Successful login
                return self._login_user('HTTP')
            else:
                logger.error('failed HTTP-Login from %s/%s %s %s %r', uid,
                             self.request.remote_addr,
                             self.request.headers.get('Authorization'),
                             self.credential, secret.strip())
                logger.info('Falsches Credential oder kein secret')
                raise exc.HTTP401_Unauthorized(
                    'Invalid HTTP-Auth Infomation',
                    headers={b'WWW-Authenticate': b'Basic realm="API Login"'})

        # 2. Check for valid Authentication via JWT via GAETK2 or Auth0 Tokens
        if self.request.headers.get('Authorization',
                                    '').lower().startswith('bearer '):
            auth_type, access_token = self.request.headers.get(
                'Authorization').split(None, 1)
            # non standards extension to allow us to transport access and id token
            id_token = None
            if ' ' in access_token:
                access_token, id_token = access_token.split(None, 1)
            logging.debug('token: %s', access_token)
            unverified_header = self.jose_jwt_get_unverified_header(
                access_token)
            if gaetkconfig.JWT_SECRET_KEY and unverified_header[
                    'alg'] == 'HS256':
                # gaetk2 JWT for internal use
                userdata = self.decode_jwt(access_token,
                                           gaetkconfig.JWT_SECRET_KEY,
                                           algorithms=['HS256'])
                # 'sub': u'*****@*****.**'}
                self.credential = check404(
                    self.get_credential(userdata['sub']),
                    'unknown uid %r' % userdata['sub'])
                # We do not check the password because get_current_user() is trusted
                return self._login_user('gaetk2 JWT')

            else:
                # Auth0 JWT, see http://filez.foxel.org/2P2o1O3j2f1N
                userdata = self.decode_jwt(access_token,
                                           get_jwt_key(
                                               unverified_header['kid']),
                                           algorithms=['RS256'])
                # For Auth0 / OpenID authentication there should be an user in our database
                self.credential = models.gaetk_Credential.query(
                    models.gaetk_Credential.external_uid ==
                    userdata['sub']).get()
                email = None
                if not self.credential:
                    # if not: can we find one by id_token?
                    if userdata.get('email_verified'):
                        email = userdata.get('email')
                    else:
                        if id_token:
                            userdata = self.decode_jwt(
                                id_token,
                                get_jwt_key(unverified_header['kid']),
                                algorithms=['RS256'],
                                access_token=access_token)
                            if userdata.get('email_verified'):
                                email = userdata.get('email')
                    if email:
                        self.credential = models.gaetk_Credential.query(
                            models.gaetk_Credential.email == email).get()
                        logging.info('%s zugeordnet', self.credential)
                        # if self.credential:
                        #     self.credential.external_uid = userdata['sub']
                        #     self.credential.put()
                self.credential = check404(self.credential,
                                           '%s not found' % userdata['sub'])
                # We do not check the password because get_current_user() is trusted
                return self._login_user('Auth0 JWT')

        # 3. Check for App Engine / Google Apps based Login
        user = users.get_current_user()
        if user:
            self.credential = self.get_credential(user.email())
            if self.credential:
                # We do not check the password because get_current_user() is trusted
                return self._login_user('Google User OpenID Connect')

        # 4. Check for session based login
        if self.session.get('uid'):
            logger.debug('trying session based login')
            self.credential = self.get_credential(self.session['uid'])
            if self.credential:
                # We do not check the password because session storage is trusted
                return self._login_user('session')
            else:
                logger.warn(
                    'No Credential for Session: %s. Progressing unauthenticated',
                    self.session.get('uid'))
                self._clear_session()

        # 5. Login for Google Special Calls from Cron & TaskQueue
        # X-AppEngine-QueueName
        # https://cloud.google.com/appengine/docs/standard/python/config/cron#securing_urls_for_cron
        # TODO:
        # x-appengine-user-is-admin
        # x-appengine-auth-domain
        # x-google-real-ip
        # https://cloud.google.com/appengine/docs/standard/python/appidentity/
        # X-Appengine-Cron: true
        if self.request.headers.get('X-AppEngine-QueueName'):
            uid = 'X-AppEngine-Taskqueue-{}'.format(
                self.request.headers.get('X-AppEngine-QueueName'))
            self.credential = models.gaetk_Credential.create(
                id=uid, uid=uid, text='created automatically via gaetk2')
            return self._login_user('AppEngine')

        # 6. Other App Engine Apps
        # X-Appengine-Inbound-Appid
        # https://cloud.google.com/appengine/docs/standard/python/appidentity/#asserting_identity_to_other_app_engine_apps
        ibaid = self.request.headers.get('X-Appengine-Inbound-Appid')
        if ibaid:
            if ibaid in gaetkconfig.INBOUND_APP_IDS:
                uid = 'X-Appengine-Inbound-Appid-{}'.format(ibaid)
                self.credential = models.gaetk_Credential.create(
                    id=uid, uid=uid, text='created automatically via gaetk2')
                return self._login_user('AppEngine')
            else:
                logging.debug(
                    'configure INBOUND_APP_IDS to allow %s access',
                    self.request.headers.get('X-Appengine-Inbound-Appid'))

        # 7. log in by Sentry bot
        # see https://blog.sentry.io/2017/06/15/notice-of-address-change
        if self.request.headers.get('X-Sentry-Token'):
            if gaetkconfig.SENTRY_SECURITY_TOKEN:
                if self.request.headers.get(
                        'X-Sentry-Token') == gaetkconfig.SENTRY_SECURITY_TOKEN:
                    uid = '*****@*****.**'
                    self.credential = models.gaetk_Credential.create(
                        id=uid,
                        uid=uid,
                        text='created automatically via gaetk2')
                    return self._login_user('Sentry')

        # 8. Test Framework
        # see https://blog.sentry.io/2017/06/15/notice-of-address-change
        if os.environ.get('GAETK2_WEBTEST'):
            uid = '*****@*****.**'
            self.credential = models.gaetk_Credential.create(
                id=uid, uid=uid, text='created automatically via gaetk2')
            return self._login_user('GAETK2_WEBTEST')

        logger.info(
            'user unauthenticated: Authorization:%r User:%r Session:%r QueueName:%r Appid:%r Sentry:%r',
            self.request.headers.get('Authorization', ''),
            users.get_current_user(),
            self.session,
            self.request.headers.get('X-AppEngine-QueueName'),
            self.request.headers.get('X-Appengine-Inbound-Appid'),
            self.request.headers.get('X-Sentry-Token'),
        )
        logger.debug('headers: %s', self.request.headers.items())
    def get(self, kind, action_or_objectid):
        """Handler, der die richtige Methode für die Aktion aufruft"""

        admin_class = check404(gaetk2.admin.site.get_admin_by_kind(kind))
        admin_class.export_view_csv(self)