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)