def module_router(moduleuri): """ """ dolog("INFO", "In module router, %s" % request.method) requesting_user_uri = g.userID payload = obtain_payload(request) if request.method == "GET": return generic_get(moduleuri, requesting_user_uri) elif request.method == "POST": if payload is None: raise Rhaptos2HTTPStatusError( "Received a Null payload, expecting JSON", code=400) else: return generic_post(model.Module, payload, requesting_user_uri) elif request.method == "PUT": if payload is None: raise Rhaptos2HTTPStatusError( "Received a Null payload, expecting JSON", code=400) else: return generic_put(model.Module, moduleuri, payload, requesting_user_uri) elif request.method == "DELETE": return generic_delete(moduleuri, requesting_user_uri) else: return Rhaptos2HTTPStatusError("Methods:GET PUT POST DELETE.")
def __init__(self, authenticated_identifier): """initialise from a id we have had verified by third party .. todo:: this is stubbed out - it should always go to user dbase and lookup fromidentifer .. todo:: what should I do if user dbase is unavilable??? .. todo:: totally unsafe laoding of user details """ payload = {'user': authenticated_identifier} user_server_url = app.config['globals'][ u'userserver'].replace("/user", "/openid") dolog("INFO", "user info - from url %s and query string %s" % (user_server_url, repr(payload))) try: r = requests.get(user_server_url, params=payload) userdetails = r.json() except Exception, e: #.. todo:: not sure what to do here ... the user dbase is down dolog("INFO", e) userdetails = None
def loginpersona(): """Taken mostly from mozilla quickstart """ dolog("INFO", "loginpersona") # The request has to have an assertion for us to verify if 'assertion' not in request.form: abort(400) # Send the assertion to Mozilla's verifier service. audience = "http://%s" % app.config['www_server_name'] data = {'assertion': request.form['assertion'], 'audience': audience} resp = requests.post( 'https://verifier.login.persona.org/verify', data=data, verify=True) # Did the verifier respond? if resp.ok: # Parse the response verification_data = json.loads(resp.content) dolog("INFO", "Verified persona:%s" % repr(verification_data)) # Check if the assertion was valid if verification_data['status'] == 'okay': # Log the user in by setting a secure session cookie # session.update({'email': verification_data['email']}) auth.after_authentication(verification_data['email'], 'persona') return resp.content # Oops, something failed. Abort. abort(500)
def crash(): ''' ''' if app.debug == True: dolog("INFO", 'crash command called', caller=crash, statsd=['rhaptos2.repo.crash',]) raise exceptions.Rhaptos2Error('Crashing on demand') else: abort(404)
def workspaceGET(): ''' ''' # TODO - should whoami redirect to a login page? ### yes the client should only expect to handle HTTP CODES ### compare on userID identity = auth.whoami() if not identity: abort(403) else: wout = {} dolog("INFO", "Calling workspace with %s" % identity.userID) w = model.workspace_by_user(identity.userID) dolog("INFO", repr(w)) ## w is a list of models (folders, cols etc). # it would require some flattening or a JSONEncoder but we just want # short form for now short_format_list = [{ "id": i.id_, "title": i.title, "mediaType": i.mediaType} for i in w] flatten = json.dumps(short_format_list) resp = flask.make_response(flatten) resp.content_type = 'application/json; charset=utf-8' resp.headers["Access-Control-Allow-Origin"] = "*" auth.callstatsd('rhaptos2.e2repo.workspace.GET') return resp
def __init__(self, user_id): """ """ dolog("INFO", "in workspace of %s" % user_id, caller=WorkSpace, statsd=['rhaptos2.repo.workspace.entered',]) self.user_id = user_id repodir = app.config['repodir'] plain = [] annotated = [] files = [os.path.join(repodir, f) for f in os.listdir(repodir) # Check for the file extension. if len(f.split('.')) < 2] for fpath in files: if not os.path.isdir(fpath): ndoc = NodeDoc() ndoc.load_from_file(fpath) if user_id in ndoc.contentrw: plain.append(os.path.basename(fpath)) annotated.append([os.path.basename(fpath), ndoc.title ]) self.files_plain = plain self.files_annotated = annotated
def allow_other_change(self, user_id): """ """ if user_id in self.contentrw: dolog("INFO", "Found %s in %s" % (user_id, self.contentrw)) return True else: dolog("INFO", "Not Found %s in %s" % (user_id, self.contentrw)) return False
def burn(): ''' ''' if app.debug == True: dolog("INFO", 'burn command called - dying hard with os._exit' , caller=crash, statsd=['rhaptos2.repo.crash',]) #sys.exit(1) #Flask traps sys.exit (threads?) os._exit(1) #trap _this_ else: abort(404)
def moduleDELETE(modname): '''support deletion of a module 200 - delete file successful 202 - queued for deletion 404 - no such file found ''' status_code = 200 headers = [] dolog("INFO", 'DELETE CALLED on %s' % modname, caller=moduleDELETE, statsd=['rhaptos2.repo.module.DELETE',]) try: jsonstr = model.delete_module(modname) except IOError, e: status_code = 404
def serve_aloha(filename): """ serve static files for development purposes We would expect that these routes would be "overwritten" by say the front portion of the reverse proxy we expect flask to sit behind. So these will only ever be called by requests during development, but the URL /cdn/aloha/... would still exist, possibly on a CDN, certainly a good cache server. """ # os.path.isfile is checked by the below function in Flask. dolog("INFO", repr((app.config["aloha_staging_dir"], filename))) return send_from_directory(app.config["aloha_staging_dir"], filename)
def index(): """ .. dicussion:: The index page for an api.cnx.org might point to say docs The index page here is the index of www.cnx, so it should serve the workspace. Which is not something "known" by the repo, hence the redirect. It may be neater to bring the index.html page into here later on. TODO: either use a config value, or bring a index template in here """ dolog("INFO", "THis is request %s" % g.requestid) return redirect("/js/")
def modulePUT(): dolog("INFO", 'MODULE PUT CALLED', caller=modulePUT, statsd=['rhaptos2.repo.module.PUT',]) try: d = request.json if d['uuid'] == u'': return ("PUT WITHOUT A UUID" , 400) current_nd = model.mod_from_file(d['uuid']) current_nd.load_from_djson(d) #this checks permis uid = current_nd.uuid current_nd.save() except Exception, e: raise(e)
def whoami(): ''' return the identity url stored in session cookie TODO: store the userid in session cookie too ? .. todo:: session assumes there will be a key of 'authenticated_identifier' .. todo:: I always go and look this up - decide if this is sensible / secure .. todo:: use secure cookie I really need to think about session cookies. Default for now. .. todo:: document fajkeuserID ''' dolog("INFO", "Whoami called", caller=whoami) if HTTPHEADER_STORING_USERURI in request.headers and app.debug is True: fakeuserid = request.headers.get(HTTPHEADER_STORING_USERURI) g.user_id = fakeuserid return Identity(fakeuserid) elif (HTTPHEADER_STORING_USERAUTH in request.headers and app.debug is True and 'authenticated_identifier' not in session): fakeuserauth = request.headers.get(HTTPHEADER_STORING_USERAUTH) after_authentication(fakeuserauth, "openid") return Identity(fakeuserauth) elif 'authenticated_identifier' in session: user = Identity(session['authenticated_identifier']) g.user_id = user.userID return user else: callstatsd("rhaptos2.repo.notloggedin") g.user_id = None g.user = None return None
def modulePOST(): """ """ dolog("INFO", 'A Module POSTed', caller=modulePOST, statsd=['rhaptos2.repo.module.POST',]) d = request.json if d['uuid'] != u'': return ("POSTED WITH A UUID" , 400) else: d['uuid'] = None #app.logger.info(repr(d)) ### maybe we know too much about nodedocs nd = model.mod_from_json(d) uid = nd.uuid nd.save() del(nd) s = model.asjson({'hashid':uid}) return s
def is_action_auth(self, action=None, requesting_user_uri=None): """ Given a user and a action type, determine if it is authorised on this object #unittest not available as setup is large. >> C = CNXBase() >> C.is_action_auth(action="PUT", requesting_user_uri="Fake1") *** [u'Fake1'] True >> C.is_action_auth(action="PUT", requesting_user_uri="ff") *** [u'Fake1'] False """ s = "*****AUTH" s += "model" + str(self) s += "action" + str(action) s += "user" + str(requesting_user_uri) s += "*****/AUTH" dolog("INFO", s) if action in ("GET", "HEAD", "OPTIONS"): valid_user_list = [u.user_uri for u in self.userroles if u.role_type in ("aclro", "aclrw")] elif action in ("POST", "PUT", "DELETE"): valid_user_list = [u.user_uri for u in self.userroles if u.role_type in ("aclrw",)] else: # raise Rhaptos2SecurityError("Unknown action type: %s" % action) return False if requesting_user_uri is None: # raise Rhaptos2SecurityError("No user_uri supplied: %s" % # requesting_user_uri) return False else: if requesting_user_uri in valid_user_list: return True else: return False
def whoami(): """ return the identity url stored in session cookie TODO: store the userid in session cookie too ? .. todo:: session assumes there will be a key of 'authenticated_identifier' .. todo:: I always go and look this up - decide if this is sensible / secure .. todo:: use secure cookie I really need to think about session cookies. Default for now. """ dolog("INFO", "Whoami called", caller=whoami) if "authenticated_identifier" in session: user = Identity(session["authenticated_identifier"]) g.user_id = user.userID return user else: callstatsd("rhaptos2.repo.notloggedin") g.user_id = None g.user = None return None
def after_authentication(authenticated_identifier, method): """Called after a user has provided a validated ID (openid or peresons) method either openid, or persona """ dolog("INFO", "in after auth - %s %s" % (authenticated_identifier, method)) dolog("INFO", "before session - %s" % repr(session)) userobj = get_user_from_identifier(authenticated_identifier) # set session, set g, set JS # session update? if method not in ('openid', 'persona'): raise Rhaptos2Error("Incorrect method of authenticating ID") session['authenticated_identifier'] = authenticated_identifier g.user = userobj dolog("INFO", "ALLG:%s" % repr(g)) dolog("INFO", "ALLG.user:%s" % repr(g.user)) dolog("INFO", "AFTER session %s" % repr(session)) return userobj
def obj_from_urn(URN, requesting_user_uri, klass=None): """ THis is the refactored version of get_by_id URN cnxmodule:1234-5678 requesting_user_urn cnxuser:1234-5678 I have reservations about encoding the type in the ID string. But not many. """ if not klass: try: klass = klass_from_uri(URN) except: dolog("INFO", "Faioled getting klass %s" % URN) abort(400) q = db_session.query(klass) q = q.filter(klass.id_ == URN) rs = q.all() if len(rs) == 0: raise Rhaptos2Error("ID Not found in this repo") ### There is a uniq constraint on the table, but anyway... if len(rs) > 1: raise Rhaptos2Error("Too many matches") newu = rs[0] if not change_approval(newu, {}, requesting_user_uri, "GET"): raise Rhaptos2AccessNotAllowedError("user %s not allowed access to %s" % (requesting_user_uri, URN)) return newu
def whoami(): ''' return the Identity object stored in session cookie TODO: store the userid in session cookie too ? .. todo:: session assumes there will be a key of 'authenticated_identifier' .. todo:: I always go and look this up - decide if this is sensible / secure .. todo:: use secure cookie I really need to think about session cookies. Default for now. .. todo:: document fajkeuserID ''' if (HTTPHEADER_STORING_USERAUTH in request.headers and app.debug is True and 'authenticated_identifier' not in session): fakeuserauth = request.headers.get(HTTPHEADER_STORING_USERAUTH) ident = after_authentication(fakeuserauth, "openid") dolog("INFO", "FAKING USER LOGIN - %s" % fakeuserauth) return ident elif 'authenticated_identifier' in session: ident = Identity(session['authenticated_identifier']) g.userID = ident.userID dolog("INFO", "Session active user is - %s" % ident.userID) return ident else: callstatsd("rhaptos2.repo.notloggedin") dolog("INFO", "not headers, not session") g.userID = None return None
def logoutpersona(): dolog("INFO", "logoutpersona") return "Yes"
def index(): dolog("INFO", "THis is request %s" % g.requestid) return render_template('index.html', confd=app.config)
def index(): dolog("INFO", "This is request %s" % g.requestid) directory = os.path.join(app.config["atc_directory"], 'test') return send_from_directory(directory, 'test-atc.html')
def serve_atc_js(): filename = 'atc.js' directory = os.path.join(app.config["atc_directory"]) filepath = os.path.join(directory, filename) dolog("INFO", filepath) return send_from_directory(directory, filename)
def serve_atc_nav_serialize_hbs(): filename = 'atc-nav-serialize.hbs' directory = os.path.join(app.config["atc_directory"]) filepath = os.path.join(directory, filename) dolog("INFO", filepath) return send_from_directory(directory, filename)
def moduleGET(modname): dolog("INFO", 'MODULE GET CALLED on %s' % modname, caller=moduleGET, statsd=['rhaptos2.repo.module.GET',]) try: jsonstr = model.fetch_module(modname) except Exception, e: raise e
def serve_bookish_css(): filename = 'bookish.css' directory = os.path.join(app.config["atc_directory"]) filepath = os.path.join(directory, filename) dolog("INFO", filepath) return send_from_directory(directory, filename)
def serve_helpers(filename): directory = os.path.join(app.config["atc_directory"], 'helpers') filepath = os.path.join(directory, filename) dolog("INFO", filepath) return send_from_directory(directory, filename)
def serve_other_thirdpartycss(filename): """ see :def:serve_aloha """ dolog("INFO", repr((app.config["css_staging_dir"], filename))) return send_from_directory(app.config["css_staging_dir"], filename)
def test_can_log(): app = make_app() dolog("WARN", "Help")