def profile(user_id): if not auth.is_logged_in(session): return redirect_to_login(STRINGS['SIGNED_OUT']) if int(user_id) == session['user_id'] or auth.is_admin(session): if request.method == 'POST': if auth.is_admin(session): email = request.form['email'] name = request.form['user-name'] suspended = request.form.get('suspended') is_admin = request.form.get('role') if suspended is None: suspended = 0 if is_admin == 'admin': is_admin = 1 else: is_admin = 0 user.edit_user_admin(user_id, email, name, suspended, is_admin) else: email = request.form['email'] name = request.form['user-name'] app.logger.debug(user_id, email, name) user.edit_user(user_id, email, name) flash("Changes saved successfully", category="success") return redirect(url_for('profile', user_id=user_id)) else: return render_template("profile.html", session=session, user=user.get_user_by_id(user_id)) else: return redirect_to_home(STRINGS['NOT_AUTHORIZED'])
def attraction_report(attraction_id): if not auth.is_logged_in(session): return redirect_to_login(STRINGS['SIGNED_OUT']) if not auth.is_admin(session): return redirect_to_home(STRINGS['NOT_AUTHORIZED']) show_date = request.args.get('date', str(dt.datetime.now())[:10]) try: time_slots = attraction.get_time_slots(attraction_id) show_time_slot = int( request.args.get('ts', time_slots[0]['time_slot_id'])) app.logger.debug(time_slots[0]['time_slot_id']) return render_template( "attractions/attraction_report.html", session=session, attraction=attraction.get_attraction(attraction_id), requires_reservation=attraction.requires_reservation( attraction_id), reservations=attraction.get_bookings(attraction_id, show_date, show_time_slot), date=show_date, time_slots=time_slots, selected_ts=attraction.get_time_slot(show_time_slot)) except IndexError: return render_template( "attractions/attraction_report.html", session=session, attraction=attraction.get_attraction(attraction_id), requires_reservation=attraction.requires_reservation( attraction_id))
def inject_config(): """Injects 'app_config' variable into jinja template, so it can be passed into angular. See base.html""" config_properties = Config.get_all_properties() if auth.is_admin( ) else Config.get_public_properties() app_config = config.CONFIG_DB.to_dict(include=config_properties) app_config['development'] = config.DEVELOPMENT return {'app_config': app_config}
def add_member(): if request.json: json = request.json access_token = json.get("accessToken") # Check that this is an admin user. if auth.is_admin(access_token) is False: return Response(status=PERMISSION_DENIED) firstname = json.get("firstname") lastname = json.get("lastname") handicap = json.get("handicap") if not firstname: return Response(status=MISSING_PARAM_CODE) if not lastname: return Response(status=MISSING_PARAM_CODE) if not handicap: return Response(status=MISSING_PARAM_CODE) else: connection = query_db.get_connection(current_db_location()) if connection is not None: query_db.insert_into_member(connection, firstname, lastname, handicap) connection.close() return Response(status=SUCCESS_CODE) else: # Connection to database failed return Response(status=FAILURE_CODE) return Response(status=FAILURE_CODE)
def edit_member(identifier): if not identifier: return Response(status=MISSING_PARAM_CODE) if request.json: json = request.json access_token = json.get("accessToken") # Check that this is an admin user. if auth.is_admin(access_token) is False: return Response(status=PERMISSION_DENIED) connection = query_db.get_connection(current_db_location()) if connection is not None: if request.method == 'PUT': # Edit member member = None member = member_obj_from_json(json, identifier) if not member: return Response(status=MISSING_PARAM_CODE) query_db.update_member(connection, identifier, member) connection.close() return Response(status=SUCCESS_CODE) elif request.method == 'DELETE': # Delete member query_db.delete_member(connection, identifier) return Response(status=SUCCESS_CODE) # Failure return Response(status=FAILURE_CODE)
def add_poy(): if request.json: json = request.json access_token = json.get('accessToken') # Check that this user is admin. if auth.is_admin(access_token) is False: return Response(status=PERMISSION_DENIED) member_id = json.get('member_id') year = json.get('year') score = json.get('score') if not member_id: return Response(status=MISSING_PARAM_CODE) else: connection = query_db.get_connection(current_db_location()) if connection is not None: query_db.insert_into_poy(connection, member_id, year, score) connection.close() return Response(status=SUCCESS_CODE) else: return Response(status=FAILURE_CODE) else: return Response(status=FAILURE_CODE)
def get(self, username): """Loads user's properties. If logged user is admin it loads also non public properties""" if auth.is_admin(): properties = User.get_private_properties() else: properties = User.get_public_properties() return g.user_db.to_dict(include=properties)
def index(level, step): session_id() # Run this for the side effect of generating a session ID g.level = level = int(level) g.lang = requested_lang() g.prefix = '/hedy' # If step is a string that has more than two characters, it must be an id of a program if step and type_check(step, 'str') and len(step) > 2: result = db_get('programs', {'id': step}) if not result: return 'No such program', 404 # Allow only the owner of the program, the admin user and the teacher users to access the program user = current_user(request) if user['username'] != result['username'] and not is_admin( request) and not is_teacher(request): return 'No such program!', 404 loaded_program = result['code'] # We default to step 1 to provide a meaningful default assignment step = 1 else: loaded_program = None return hedyweb.render_assignment_editor(request=request, course=HEDY_COURSE[g.lang], level_number=level, assignment_number=step, menu=render_main_menu('hedy'), translations=TRANSLATIONS, version=version(), loaded_program=loaded_program)
def add_result(): if request.json: json = request.json access_token = json.get("accessToken") # Check that this is an admin user. if auth.is_admin(access_token) is False: return Response(status=PERMISSION_DENIED) event_id = json.get("event_id") member_id = json.get("member_id") score = json.get("score") if not event_id: return Response(status=MISSING_PARAM_CODE) if not member_id: return Response(status=MISSING_PARAM_CODE) if not score: return Response(status=MISSING_PARAM_CODE) else: connection = query_db.get_connection(current_db_location()) if connection is not None: query_db.insert_into_result(connection, event_id, member_id, score) connection.close() return Response(status=SUCCESS_CODE) else: # Connection to database failed return Response(status=FAILURE_CODE) # Failure return Response(status=FAILURE_CODE)
def get(self, key): """Loads expense type's properties.""" if auth.is_admin(): properties = model.ExpenseType.get_private_properties() else: properties = model.ExpenseType.get_public_properties() return g.model_db.to_dict(include=properties)
def programs_page (request): username = current_user(request) ['username'] if not username: return "unauthorized", 403 lang = requested_lang() query_lang = request.args.get('lang') or '' if query_lang: query_lang = '?lang=' + query_lang from_user = request.args.get('user') or None if from_user and not is_admin (request): return "unauthorized", 403 texts=TRANSLATIONS.data [lang] ['Programs'] result = db_get_many ('programs', {'username': from_user or username}, True) programs = [] now = timems () for item in result: measure = texts ['minutes'] date = round ((now - item ['date']) / 60000) if date > 90: measure = texts ['hours'] date = round (date / 60) if date > 36: measure = texts ['days'] date = round (date / 24) programs.append ({'id': item ['id'], 'code': item ['code'], 'date': texts ['ago-1'] + ' ' + str (date) + ' ' + measure + ' ' + texts ['ago-2'], 'level': item ['level'], 'name': item ['name']}) return render_template('programs.html', lang=requested_lang(), menu=render_main_menu('programs'), texts=texts, auth=TRANSLATIONS.data [lang] ['Auth'], programs=programs, username=username, current_page='programs', query_lang=query_lang, from_user=from_user)
def put(self, key): """Updates user's properties""" update_properties = ['name', 'bio', 'email', 'location', 'avatar_url', 'facebook', 'github', 'gplus', 'linkedin', 'twitter', 'instagram'] if auth.is_admin(): update_properties += ['verified', 'active', 'admin'] new_data = _.pick(request.json, update_properties) g.model_db.populate(**new_data) g.model_db.put() #return make_empty_ok_response() if auth.is_admin(): properties = User.get_private_properties() else: properties = User.get_public_properties() return g.model_db.to_dict(include=properties)
def get_tickets(db, user): tickets = query(db, "select * from student_schedules where student_id = ?", user, symbolize_names=False) student = query( db, "select student_username, time_allowed_in, num from students where student_id = ?", user)[0] name = student.student_username time_allowed_in = student.time_allowed_in num = student.num waitlists = query(db, "select * from waitlist where student_id = ?", user, symbolize_names=False) comments = query(db, "select * from comments where student_id = ?", user, symbolize_names=False) return { "tickets": tickets, "name": name, "admin": auth.is_admin(user), "time_left": time_allowed_in - time.time(), "num": num, "waitlists": waitlists, "comments": comments, }
def get(self, username): """Loads user's properties. If logged user is admin it loads also non public properties""" if auth.is_admin(): properties = User.get_private_properties() else: properties = User.get_public_properties() traveler_key = getattr(g.user_db,'fellow_traveler',None) if traveler_key: traveler = traveler_key.get() future=False else: traveler = model.FellowTraveler.create_or_update( name=g.user_db.name, email=g.user_db.email, avatar_url=g.user_db.avatar_url, parent=g.user_db.key, added_by=g.user_db.key) traveler_key =traveler.put() traveler.key = traveler_key g.user_db.fellow_traveler = traveler_key future = g.user_db.put_async() db_dict = g.user_db.to_dict(include=properties) db_dict["fellow_traveler"] = traveler.to_dict(include=model.FellowTraveler.get_public_properties()) if future: future.get_result() return db_dict
def create_attraction(): if not auth.is_logged_in(session): return redirect_to_login(STRINGS['SIGNED_OUT']) if not auth.is_admin(session): return redirect_to_home(STRINGS['NOT_AUTHORIZED']) if request.method == 'POST': name = request.form["name"] description = request.form["description"] price = request.form["price"] if request.form["street_num"] == "": street_num = None else: street_num = request.form["street_num"] street = request.form["street"] city = request.form["city"] if request.form["state"] == "": state = None else: state = request.form["state"] zip = request.form["zip"] country = request.form["country"] if request.form["transit"] == "": transit = None else: transit = request.form["transit"] attraction.create_attraction(name, description, price, street_num, street, city, state, zip, country, transit) flash("Attraction created successfully", category="success") return redirect(url_for('admin')) return render_template("attractions/attraction.html", session=session)
def get_resource(collection,category,name): # TODO auth.is_admin and collectio permission does not work !!! -> used True or if True or auth.is_admin() or model.Collection.has_permission(collection,auth.current_user_key().urlsafe(),'read',urlsafe=True): adr = BUCKET + '/' + collection + '/' + category + '/' + name blob_key = blobstore.create_gs_key('/gs' + adr) img_url = images.get_serving_url(blob_key=blob_key) print img_url return flask.redirect(img_url)
def inject_config(): """Injects 'app_config' variable into jinja template, so it can be passed into angular. See base.html""" config_properties = Config.get_all_properties() if auth.is_admin() else Config.get_public_properties() app_config = config.CONFIG_DB.to_dict(include=config_properties) app_config['development'] = config.DEVELOPMENT return { 'app_config': app_config }
def post(self, key): """Updates simulation's properties""" update_properties = ['name', 'description', 'location', 'soil_attributes', 'start_date', 'end_date', 'crop_name', 'sowing_date', 'tsum1', 'tsum2'] if auth.is_admin(): update_properties += ['owner_id'] new_data = _.pick(request.json, update_properties) print("SAVE POST: Received simulation data: ", new_data) g.model_db.populate(**new_data) g.model_db.put() #return make_empty_ok_response() if auth.is_admin(): properties = Simulation.get_private_properties() else: properties = Simulation.get_public_properties() return g.model_db.to_dict(include=properties)
def post(self, key): """Updates user's properties""" update_properties = [ 'name', 'bio', 'email', 'location', 'avatar_url', 'facebook', 'github', 'gplus', 'linkedin', 'twitter', 'instagram' ] if auth.is_admin(): update_properties += ['verified', 'active', 'admin'] new_data = _.pick(request.json, update_properties) g.model_db.populate(**new_data) g.model_db.put() #return make_empty_ok_response() if auth.is_admin(): properties = User.get_private_properties() else: properties = User.get_public_properties() return g.model_db.to_dict(include=properties)
def delete_attraction(attraction_id): if not auth.is_logged_in(session): return redirect_to_login(STRINGS['SIGNED_OUT']) if not auth.is_admin(session): return redirect_to_home(STRINGS['NOT_AUTHORIZED']) attraction.delete_attraction(attraction_id) flash("Attraction deleted successfully", category='success') return redirect(url_for('admin'))
def remove_comment(comment_id): if auth.is_admin(): data.remove_comment(comment_id) return json.dumps({ 'success': True, 'message': '', }) else: flask.abort(403)
def get(self, username): parser = reqparse.RequestParser() parser.add_argument('cursor', type=ArgumentValidator.create('cursor')) parser.add_argument('q', type=str,default='') parser.add_argument('size', type=int,default=10) args = parser.parse_args() # current user key user_key = g.user_db.key if auth.is_admin() or user_db.key == auth.current_user_key(): query = model.CollectionUser.qry(user=user_key) collection_keys_future = query.fetch_async(limit=args.size*4,keys_only=True) # do something else here? collection_keys = collection_keys_future.get_result() collection_keys = [key.parent() for key in collection_keys] # Search for users in this collections users = []; for key in collection_keys: query = model.CollectionUser.query(ancestor=key) if len(args.q) > 2: query = query \ .filter(model.CollectionUser.user.username >= args.q) \ .filter(model.CollectionUser.user.username <= unicode(args.q) + u"\ufffd")\ .order(model.CollectionUser.user.username) else: query = query.order(model.CollectionUser.modified) users_future = query.fetch_async( limit=args.size, projection=['modified','user.username','user.email','user.avatar_url','user_key']) users = users + users_future.get_result() #users = users + [{'key':u.key,'modified':u.modified} for u in users_future.get_result()] # check if a user with this name or email exists: user_db = model.User.get_by_email_or_username(args.q) if len(args.q)>2 else None if user_db: # create temp user with modified now -> first in list user = model.CollectionUser( user_key= user_db.key, user = model.User(username = user_db.username, email = user_db.email, avatar_url = user_db.avatar_url), name = "Just Temp User", modified = datetime.datetime.now(), created = datetime.datetime.now() ) users.append(user) # sort users after its last modification users = util.sort_uniq(users,'modified','user_key',reverse=False) #users = [u.urlsafe() for u in users] users = [u.to_dict(include=['modified','user','user_key']) for u in users] total = len(users) if total > args.size: users = users[:args.size] return make_list_response(users, None, total > args.size, total)
def get(self,collection,category,name): """Updates user's properties""" if auth.is_admin() or model.Collection.has_permission(collection,auth.current_user_key().urlsafe(),'read',urlsafe=True): adr = BUCKET + '/' + collection + '/' + category + '/' + name blob_key = blobstore.create_gs_key('/gs' + adr) img_url = images.get_serving_url(blob_key=blob_key) return img_url return "No permission" properties = model.Collection.get_private_properties() properties = model.Collection.get_public_properties() return g.model_db.to_dict(include=properties+['permission','permissionNr'])
def put(self): data = request.json print("PUT: Received simulation data: ", data) sim = Simulation(**data) sim.update_simulation_results() sim.put() if auth.is_admin(): properties = Simulation.get_private_properties() else: properties = Simulation.get_public_properties() return sim.to_dict(include=properties)
def delete_user(user_id): if not auth.is_logged_in(session): return redirect_to_login(STRINGS['SIGNED_OUT']) if not auth.is_admin(session): return redirect_to_home(STRINGS['NOT_AUTHORIZED']) if int(user_id) == session['user_id']: flash("You can't delete your own account") else: user.delete_user(user_id) flash("User deleted successfully", category="success") return redirect(url_for('admin'))
def get(self, key): """Loads expense type's properties.""" if auth.is_admin(): properties = model.Trip.get_private_properties() else: properties = model.Trip.get_public_properties() g.model_db.locations = ndb.get_multi(g.model_db.locations) i = 0 for loc in g.model_db.locations: g.model_db.locations[i].fellow_travelers = ndb.get_multi(g.model_db.locations[i].fellow_travelers) i += 1 return g.model_db.to_dict(include=properties)
def edit_poy(member_id): if request.method == 'PUT': json = request.json access_token = json.get('accessToken') new_member_id = json.get('member_id') year = json.get('year') score = json.get('score') # Check that this is an admin user. if auth.is_admin(access_token) is False: return Response(status=PERMISSION_DENIED) connection = query_db.get_connection(current_db_location()) if connection is None: return Response(status=FAILURE_CODE) query_db.update_poy(connection, member_id, new_member_id, year, score) connection.close() return Response(status=SUCCESS_CODE) elif request.method == 'DELETE': json = request.json access_token = json.get('accessToken') year = json.get('year') # Check that this is an admin user. if auth.is_admin(access_token) is False: return Response(status=PERMISSION_DENIED) connection = query_db.get_connection(current_db_location()) if connection is None: return Response(status=FAILURE_CODE) query_db.delete_poy(connection, member_id, year) connection.close() return Response(status=SUCCESS_CODE) else: # Failure return Response(status=FAILURE_CODE)
def put(self, key): """Updates user's properties""" update_properties = [ 'name', 'bio', 'email', 'location', 'facebook', 'github', 'gplus', 'linkedin', 'twitter', 'instagram' ] if auth.is_admin(): update_properties += ['verified', 'active', 'admin'] new_data = _.pick(request.json, update_properties) g.model_db.populate(**new_data) g.model_db.put() return make_empty_ok_response()
def login(): if request.method == 'POST': username = request.form.get('user') password = request.form.get('pass') endpoint = request.form.get('endpoint') if auth.auth(username, password): session['username'] = username session['admin'] = auth.is_admin(username) flash('Login successfull.', 'success') else: flash('Login failed.', 'error') return redirect(url_for(endpoint)) return redirect(url_for('index'))
def admin(): if not auth.is_logged_in(session): return redirect_to_login(STRINGS['SIGNED_OUT']) if not auth.is_admin(session): return redirect_to_home(STRINGS['NOT_AUTHORIZED']) return render_template("admin.html", session=session, users=user.get_all_users(), attractions=attraction.get_all(), res_info=attraction.requires_reservation_all()) return render_template("admin.html", session=session, users=user.get_all_users(), attractions=attraction.get_all())
def GET(self, variables={}): name = self.__class__.__name__.replace('Controller', '').lower() defaults = { 'user' : auth.user(), 'admin' : auth.is_admin(), 'path' : web.ctx.path } defaults.update(variables) if auth.user(): lastonline = LastOnline.get_by_key_name(str(auth.user().user_id())) if not lastonline: lastonline = LastOnline(key_name=str(auth.user().user_id()), uid=str(auth.user().user_id())) lastonline.put() return jinja_environment.get_template( 'templates/%s.html' % (name,) ).render(defaults)
def login(): if request.json: json = request.json fb_id = json.get('fb_id') # Check to see if that fb id is the # id of the admin stored on disk. data = '' if auth.is_admin(fb_id) == True: data = '{"isAdmin" : true }' else: data = '{"isAdmin" : false }' return Response(status=SUCCESS_CODE, response=data, mimetype='application/json') else: # Failure return Response(status=FAILURE_CODE)
def GET(self, name=None): if auth.is_admin(): found_name = False if name: q = Profile.all().filter('uid =', name).get() if q: found_name = True return self.individual_profile(q) if not found_name: results = dict() for profile in db.GqlQuery("SELECT * FROM Profile"): results[profile.uid] = profile for l in db.GqlQuery("SELECT * FROM LastOnline"): if l.uid in results: results[l.uid].last_online = l.last_online return super(self.__class__, self).GET({'students' : results}) else: return "Access Denied!"
def edit_result(): result = None if request.method == 'PUT': json = request.json access_token = json.get("accessToken") # Check that this is an admin user. if auth.is_admin(access_token) is False: return Response(status=PERMISSION_DENIED) result = result_obj_from_json(json) # All fields of the result object should be filled. if not result: return Response(status=MISSING_PARAM_CODE) connection = query_db.get_connection(current_db_location()) if connection is None: return Response(status=FAILURE_CODE) query_db.update_result(connection, result, member_id_key, event_id_key) connection.close() return Response(status=SUCCESS_CODE) elif request.method == 'DELETE': json = request.json member_id = json.get("member_id") event_id = json.get("event_id") if not member_id or not event_id: return Response(status=MISSING_PARAM_CODE) connection = query_db.get_connection(current_db_location()) if connection is None: return Response(status=FAILURE_CODE) query_db.delete_result(connection, member_id, event_id) connection.close() return Response(status=SUCCESS_CODE) else: # Failure return Response(status=FAILURE_CODE)
def add_event(): if request.json: json = request.json access_token = json.get("accessToken") # Check that this is an admin user. if auth.is_admin(access_token) is False: return Response(status=PERMISSION_DENIED) title = json.get("title") location = json.get("location") start_tee = json.get("startTeeTime") end_tee = json.get("endTeeTime") date = json.get("date") formatted_date = None # Check date format. if datetime.strptime(date, '%d-%m-%Y'): formatted_date = Event.date_format_yyyymmdd(date) else: return Response(FAILURE_CODE) if not title: return Response(status=MISSING_PARAM_CODE) if not location: return Response(status=MISSING_PARAM_CODE) if not start_tee: return Response(status=MISSING_PARAM_CODE) if not date: return Response(status=MISSING_PARAM_CODE) else: connection = query_db.get_connection(current_db_location()) if connection is not None: query_db.insert_into_event(connection, title, location, formatted_date, start_tee, end_tee) connection.close() return Response(status=SUCCESS_CODE) else: # Connection to database failed return Response(status=FAILURE_CODE) # Failure return Response(status=FAILURE_CODE)
def post(self, key): """Updates user's properties""" update_properties = [ 'first_name', 'last_name', 'avatar_url', 'email', 'username' ] if auth.is_admin(): update_properties += ['verified', 'active', 'admin'] new_user_data = _.pick(request.json, update_properties) new_email_set = False new_email = new_user_data.get('email') if new_email != g.model_db.email: UserValidator.create('unique_email')(new_email) new_email_set = True new_username = new_user_data.get('username') if new_username != g.model_db.username: UserValidator.create('unique_username')(new_username) g.model_db.populate(**new_user_data) g.model_db.put() return g.model_db.to_dict(include=User.get_public_properties())
def removeImage(): if request.method == 'DELETE': json = request.json access_token = json.get('accessToken') event_id = json.get('event_id') image_id = json.get('image_id') # Check that this is an admin user. if auth.is_admin(access_token) is False: return Response(status=PERMISSION_DENIED) connection = query_db.get_connection(current_db_location()) if connection is None: return Response(status=FAILURE_CODE) else: query_db.delete_event_image(connection, image_id) connection.close() # Remove image from disk aswell. image_parent_dir = IMAGE_BASE_DIRECTORY + str(event_id) + '/' image_util.delete_image(image_parent_dir, str(image_id) + '.jpg') return Response(status=SUCCESS_CODE)
def put(self, key): """Updates user's properties""" update_properties = [ "name", "bio", "email", "location", "facebook", "github", "gplus", "linkedin", "twitter", "instagram", ] if auth.is_admin(): update_properties += ["verified", "active", "admin"] new_data = _.pick(request.json, update_properties) g.model_db.populate(**new_data) g.model_db.put() return make_empty_ok_response()
def add_event_image(): if request.json: json = request.json access_token = json.get("accessToken") # Check that this is an admin user. if auth.is_admin(access_token) is False: return Response(status=PERMISSION_DENIED) # Get json objects image_encoding = json.get("image_encoding") event_id = json.get("event_id") image_base64_data = json.get("image_data") # Images should be stored in a directory # under IMAGE_BASE_DIRECTORY > event id > filename. # Where the filename is the actual id of the image given by the database. # e.g. files will be stored IMAGE_BASE_DIRECTORY/EVENT_ID/2.jpeg, # IMAGE_BASE_DIRECTORY/EVENT_ID/3.jpeg etc... # Create parent directory where the image file will reside. image_parent_dir = IMAGE_BASE_DIRECTORY + str(event_id) + '/' # Get database connection connection = query_db.get_connection(current_db_location()) # If there is not image type, encode as jpg. if image_encoding is None: # Insert into the database and retrieve the id for the image. # The id will be used as the image filename. image_filename = query_db.insert_into_event_image(connection, event_id, image_parent_dir, 'JPEG') image_util.jpeg_and_write_image(image_parent_dir, image_filename, image_base64_data) return Response(status=SUCCESS_CODE) else: return Response(status=FAILURE_CODE)
def edit_event(identifier): if not identifier: return Response(status=MISSING_PARAM_CODE) if request.json: json = request.json access_token = json.get("accessToken") # Check that this is an admin user. if auth.is_admin(access_token) is False: return Response(status=PERMISSION_DENIED) connection = query_db.get_connection(current_db_location()) if connection is not None: if request.method == 'PUT': # Edit existing event. event = event_obj_from_json(json, identifier) if not event: return Response(status=MISSING_PARAM_CODE) # Check date format. if datetime.strptime(event.date, '%d-%m-%Y'): formatted_date = Event.date_format_yyyymmdd(event.date) event.date = formatted_date else: return Response(FAILURE_CODE) query_db.update_event(connection, identifier, event) connection.close() return Response(status=SUCCESS_CODE) elif request.method == 'DELETE': # Delete existing event query_db.delete_event(connection, identifier) connection.close() return Response(status=SUCCESS_CODE) # Failure return Response(status=FAILURE_CODE)
def newfn(db, user, *args, **kwargs): if not auth.is_admin(user): abort(400, "You are not an administrator") return fn(db, user, *args, **kwargs)
#!/usr/bin/env python3 import cgitb import sys from auth import is_admin cgitb.enable() sys.stdout.write('Content-Type: application/octet-stream\n\n') sys.stdout.write('yes' if is_admin() else 'no') sys.stdout.flush()
def map_preview_auth(self, resource_id, user_gs_layer): """ Authorization check for the given resource ID and Geoserver layer name :param resource_id: resource_id embedded in map preview URL :param user_gs_layer: Geoserver layer name requested by user in the URL :return: """ """ Test cases: User mpeterman-msea-read. Testing with dataset: https://www.gis-hub.ca/dataset/test05. This dataset has a mixture of resources with restrictions. Test the following URLs: 1. This resource is accessible to all users in the MSEA org: https://www.gis-hub.ca/dataset/test05/map_preview/7fad5dba-b70e-4a01-b692-a59a9b1b100c Result: 200 Access OK 2. Accessible only to user dfo or admins: https://www.gis-hub.ca/dataset/test05/map_preview/b1a24c96-eaa6-4433-a706-99854894be13 Experimenting with NGINX URL rewrite and variable capture https://www.gis-hub.ca/nginx_auth/geoserver/rest/workspaces/hubdata/datastores/maps.gis-hub.ca/featuretypes/ia_geography_pncima_ia_oceanography_pncima.json https://www.gis-hub.ca/geoserver/rest/workspaces/hubdata/datastores/maps.gis-hub.ca/featuretypes/ia_geography_pncima_ia_oceanography_pncima.json Capture block in nginx has changed, the above URLs should now be: https://www.gis-hub.ca/map_preview/test05/7fad5dba-b70e-4a01-b692-a59a9b1b100c https://www.gis-hub.ca/map_preview/test05/b1a24c96-eaa6-4433-a706-99854894be13 This NGINX location block matches after /geoserver, but it removes all the URL params after ? So, /hubdata/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap... etc gets reduced to: /hubdata/wms # location ~ ^/map_preview/(?<package_id>.+)/(?<resource_id>.+)/geoserver/(?<geo_params>.+)$ { Need to add $query_string to the end of the proxy URI that gets passed on to geoserver on maps.gis-hub.ca set $geoserver_uri "https://maps.gis-hub.ca/geoserver/$geo_params?$query_string"; Have to open this in a Chrome Private window, because there was some cached HTTP basic auth that it tried to use. This works! We get the dataset and resource id, check it against CKAN auth, if it passes, we construct the correct geoserver URL and pass it to the proxy. With a geoserver request appended, test proxy. https://www.gis-hub.ca/map_preview/test05/7fad5dba-b70e-4a01-b692-a59a9b1b100c/geoserver/hubdata/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&LAYERS=hubdata%3Aenv_layers_nsbssb_bpi_medium&exceptions=application%2Fvnd.ogc.se_inimage&SRS=EPSG%3A3857&STYLES=&WIDTH=873&HEIGHT=801&BBOX=-15384022.060787713%2C5832451.006272089%2C-13248677.23861303%2C7791684.915277727 Test with a restricted resource, should fail: https://www.gis-hub.ca/map_preview/test05/b1a24c96-eaa6-4433-a706-99854894be13/geoserver/hubdata/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&LAYERS=hubdata%3Aenv_layers_nsbssb_bpi_medium&exceptions=application%2Fvnd.ogc.se_inimage&SRS=EPSG%3A3857&STYLES=&WIDTH=873&HEIGHT=801&BBOX=-15384022.060787713%2C5832451.006272089%2C-13248677.23861303%2C7791684.915277727 Yes, this request never makes it to the proxy, the auth check in nginx fails with error 500. For now, just during development, we can keep the previous /geoserver proxy open, so that map previews will continue to work. TODO: ensure that the resource being requested matches the WMS or vector layer in Geoserver. This can be deferred for now. We dont care about requests like /vector/:dataset/:layer_name. The only thing we care about is securing actual map tile requests. Probably need to also add the resource ID to the map preview URL, something like: A: /vector/:dataset/:layer_name/:resource_id. Then, inside the vector tiles template, use a URL like this: B: {{ host }}/map_preview/{{dataset}}/{{resource_id}}/geoserver/gwc/service/tms/1.0.0/hubdata:{{ layer_name }}... This will be sent to nginx auth, then proxy directly to: C: https://maps.gis-hub.ca/geoserver/$geo_params?$query_string << this part does not touch the Node.js mapserver middleware at all. And this all happens *inside NGINX*, the only URL the user's browser sees is A and B ** Update May 20. For some reason, the map_preview endpoint has stopped working. e.g. https://www.gis-hub.ca/dataset/test05/map_preview/7fad5dba-b70e-4a01-b692-a59a9b1b100c throws not found, this controller function is not called at all. > Because I renamed the function to map_preview_auth! Test this with: https://maps.gis-hub.ca/vector/ia_geography_pncima/ia_oceanography_pncima/f63a3614-84ae-4168-b340-6919eac458c6 DOES NOT WORK because: ia_geography_pncima > in CKAN this should be ia-geography-pncima with HYPHENS However in mapserver backend, it is using ia_geography_pncima + resource title with UNDERSCORES to check map extent and so on. Need to replace the dataset part of the map preview URL with ia-geography-pncima, then in the Node backend, convert this to underscores before generating postgis layer name. Postgis is not happy with table names containing hyphens. What a pain. Change to: https://maps.gis-hub.ca/vector/ia-geography-pncima/ia_oceanography_pncima/f63a3614-84ae-4168-b340-6919eac458c6 Now the last issue we have is that when the request gets proxied from maps.gis-hub.ca back to gis-hub, it no longer has the CKAN context object with the user. Is is possible to pass the session with the proxied headers? If not, we might have to redo the map preview code inside a CKAN extension (where we know for sure that we have the context). This would simplify things somewhat, no need for all the proxying between the two servers. https://maps.gis-hub.ca/vector/ia-geography-pncima/ia_oceanography_pncima/f63a3614-84ae-4168-b340-6919eac458c6 https://gis-hub.ca/vector/ia-geography-pncima/ia_oceanography_pncima/f63a3614-84ae-4168-b340-6919eac458c6 Finally, in the nginx conf inside mapserver, allow access /geoserver/gwc and /geoserver/hubdata/wms only through host gis-hub.ca. Geoserver admins need to use the Geoserver web interface, which is accessed directly through maps.gis-hub.ca:8080, which bypasses Nginx entirely. That interface is already secured with an admin pass. """ logger.info('Check if user is admin') if auth.is_admin(c.user): # Return success immediately if user is admin logger.warning('User %s is admin. Skipping all auth checks' % c.user) return render('restricted/restricted_ok_page.html') auth_status = False try: # Get resource object resource = model.Resource.get(resource_id) if not resource: logger.warning('Resource %s not found!' % resource_id) flask_abort(401, 'Access denied') resource = resource.as_dict() # Ensure that the Geoserver layer name requested by the user matches the resource # Get the internal layer name used in Geoserver, directly from metadata if exists gs_layer_name = resource.get('geoserver_layer') if gs_layer_name: if user_gs_layer != gs_layer_name: logger.warning( 'User requested a layer name not from this resource! %s, expected %s' % (user_gs_layer, gs_layer_name)) flask_abort(401, 'Invalid geoserver layer name') else: # If the geoserver_layer field does not exist, get layer name from map_preview_link field logger.warning( 'Field geoserver_layer is empty, try map_preview_link') match_ok = self.check_geoserver_layer_name( resource, user_gs_layer) if not match_ok: logger.warning( 'User requested a layer name not from this resource! %s' % user_gs_layer) flask_abort(401, 'Invalid geoserver layer name') package_id = resource.get('package_id') # Get package object using package_id from the resource package = model.Package.get(package_id) if not package: msg = 'Dataset %s not found!' % package_id logger.warning(msg) logger.warning( 'Were HYPHENS in the dataset name changed to UNDERSCORES?') flask_abort(401, msg) package = package.as_dict() logger.info( 'Checking access for User: %s, Resource: %s, Geoserver layer: %s, Package: %s' % (c.user, resource.get('title'), user_gs_layer, package.get('name'))) # Ready to check access authorized = restricted_logic.restricted_check_user_resource_access( c.user, resource, package) auth_status = authorized.get('success') logger.info('Status: %s' % auth_status) except: # If anything else goes wrong, throw an error back to Nginx logger.warning( 'Something went wrong during auth check. Return error 401') import traceback logger.error(traceback.format_exc()) flask_abort(401, 'Error in auth check') if auth_status: """ Return a normal page with status code 2xx IF the user is authorized for this resource. Nginx responds to a 2xx status code by passing the auth request, then continues with the proxy to maps.gis-hub.ca/geoserver. """ return render('restricted/restricted_ok_page.html') else: """ This causes the server to throw error 500, which is OK because anything other than a 2xx code causes Nginx to fail the auth request, and deny the proxy. User will see an error in their browser. https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-subrequest-authentication/ """ return base.abort(404, _(u'User not authorized'))
def only_admins_authorized(token): print token if not is_admin(token): abort(401, message="Only admins can make this operation")
def get(self, collection,query): parser = reqparse.RequestParser() parser.add_argument('cursor', type=ArgumentValidator.create('cursor')) #parser.add_argument('q', type=str,default='') parser.add_argument('size', type=int,default=30) parser.add_argument('only_names', type=ArgumentValidator.create('boolTrue'),default=False) args = parser.parse_args() tags = [] try: collection = ndb.Key(urlsafe=collection) except: collection = model.Collection.top_key() # Check if the user has read permission for the collection TODO if auth.is_admin(): # check if name is already a full tag key = model.Tag.tag_to_key(query,collection) try: db = key.get() except: key = model.Tag.tag_to_key(query) try: db = key.get() except: db = False if db: dbs_related, more = db.related(char_limit=200) #tags = [db.name] + db.related() tags = [r.related_to for r in dbs_related] tags = [db.name] + tags else: gae_qry = model.Tag.query(model.Tag.collection == collection) if len(query) > 1: gae_qry = gae_qry \ .filter(model.Tag.name >= query) \ .filter(model.Tag.name <= unicode(query) + u"\ufffd")\ .order(model.Tag.name) else: gae_qry = gae_qry.order(model.Tag.cnt) tags_future = gae_qry.fetch_async( limit=args.size, projection=['name']) tags = tags_future.get_result() tags = [r.name for r in tags] rel_tags = [] for tag in tags: key = model.Tag.tag_to_key(tag,collection) try: db = key.get() if db: dbs_related, more = db.related(char_limit=100) rel_tags = [r.related_to for r in dbs_related] tags = tags+rel_tags #[:5] except: pass if len(tags) > args.size+5: break #tags = list(set(tags)) tags = list(OrderedDict.fromkeys(tags)) total = len(tags) tags = tags[:args.size] if not args.only_names: tags = model.Tag.get_tag_infos(tags,collection) return make_list_response(tags, False, total > len(tags), total)